Data preparation script for Sierra Nevada time series analysis

# 1. Read in isotope data from various sources
# First load helper functions 'read_jena_ams_results.R', 'read_jena_iso_results.R' 
source("./utilities/jena_ams_ingest.R")
source("./utilities/jena_iso_ingest.R")
source("./utilities/jena_elm_ingest.R")
# color palettes for ECO & PM
warm <- "#BF812D"
cool <- "#80CDC1"
cold <- "#01665E"
granite <- "#9daba9"
andesite <- "#382dbf"
basalt <- "#bf382d"
# Create template for bulk soil data
template19.fx <- function(pm, eco, ndepth) {
  df <- data.frame(Year = rep(2019, ndepth * 3),
                   PM = rep(pm, ndepth * 3),
                   ECO = rep(eco, ndepth * 3),
                   pro_rep = rep(seq(1,3), each = ndepth),
                   lyr_top = rep(seq(0, (ndepth-1) * 10, by = 10), 3),
                   lyr_bot = rep(seq(10, (ndepth) * 10, by = 10), 3))
  df$pro_name <- paste0(df$PM, df$ECO, "_", df$pro_rep)
  df$lyr_name <- paste0(df$pro_name, "_", df$lyr_top, "-", df$lyr_bot)
  return(df)
}

# Create template for composite soil data (incubations, density fractions, etc.)
template.comp.fx <- function(year, pm, eco, depth_bot = c(10, 20, 30), dat) {
  ndepth <- length(depth_bot)
  df <- data.frame(Year = rep(year, ndepth * length(pm)),
                   PM = rep(pm, each = ndepth * length(eco)),
                   ECO = rep(eco, each = ndepth))
  df$lyr_bot <- depth_bot
  df$lyr_top <- sapply(seq_along(depth_bot), function(i) {
    if (i == 1) {
      depth_top <- 0
      } else {
        depth_top <- depth_bot[i - 1]
      }
  })
  df$pro_name <- paste0(df$PM, df$ECO, "_comp")
  n <- nrow(df)
  if (dat == "inc") {
    df <- rbind(df, df)
    df$rep <- rep(c("a", "b"), each = n)
    df$lyr_name <- paste0(df$pro_name, "_", 
                          df$lyr_top, "-", 
                          df$lyr_bot, "_", 
                          df$Year, "_",
                          df$rep)
  } else if (dat == "density") {
    df <- rbind(df, df, df)
    df$frc <- rep(c("fLF", "oLF", "mnC"), each = n)
    df$lyr_name <- paste0(df$pro_name, "_", 
                          df$lyr_top, "-", 
                          df$lyr_bot, "_", 
                          df$Year, "_",
                          df$frc)
  }
  return(df)
}

# templates for bulk soil data
# GRrf 
GRrf <- template19.fx("GR", "rf", 7)
GRrf <- if(any(GRrf$lyr_name == "GRrf_1_60_70")) {
  GRrf <- GRrf[-which(GRrf$lyr_name == "GRrf_1_60_70"), ] # NB: GRrf_1_60_70 doesn't exist
} else {
  GRrf <- GRrf
}
# GRwf
GRwf <- template19.fx("GR", "wf", 9)
# GRpp
GRpp <- template19.fx("GR", "pp", 8)

# ANrf 
ANrf <- template19.fx("AN", "rf", 6)
# ANwf
ANwf <- template19.fx("AN", "wf", 6)
# ANpp
ANpp <- template19.fx("AN", "pp", 8)

# BSrf 
BSrf <- template19.fx("BS", "rf", 8)
BSrf <- if(any(BSrf$lyr_name == "GRrf_1_60_70")) {
  BSrf <- BSrf[-which(BSrf$lyr_name == "BSrf_1_70_80"), ] # NB: BSrf_1_70_80 doesn't exist
} else {
  BSrf <- BSrf
} 
# BSwf
BSwf <- template19.fx("BS", "wf", 7)
# BSpp
BSpp <- template19.fx("BS", "pp", 8)
BSpp[BSpp$lyr_bot == 80, "lyr_bot"] <- 75 # only sampled to 75cm, not 80

sra.2019.df <- rbind(GRrf, GRwf, GRpp,
                     ANrf, ANwf, ANpp,
                     BSrf, BSwf, BSpp)

# template for 2019 incubation data
sra.2019.inc.df <- template.comp.fx(2019, 
                                    pm = c("AN", "BS", "GR"),
                                    eco = c("pp", "wf", "rf"),
                                    dat = "inc")

## template for 2001 incubation data
# list of depths for 2001 inc samples
depth_bot_2001.ls <- list(ANpp = c(6, 13, 33),
                          ANwf = c(11, 35),
                          ANrf = c(11, 32),
                          BSpp = c(7, 18, 28),
                          BSwf = c(10, 19),
                          BSrf = c(8, 15, 30),
                          GRpp = c(7, 15, 27),
                          GRwf = c(4, 13, 28),
                          GRrf = c(8, 27)) 
# template for inputs to template.comp.fx (year, pm, eco)
inc.2001.template <- lapply(seq_along(depth_bot_2001.ls), function(i) {
  nms <- names(depth_bot_2001.ls)
  ls <- list(year = 2001, 
             pm = substr(nms[i], 1, 2), 
             eco = substr(nms[i], 3, 4))
  ls$depth_bot <- depth_bot_2001.ls[[i]]
  return(ls)
})
# create template data frame by iteratively calling template.comp.fx
sra.2001.inc.df <- bind_rows(
  lapply(seq_along(inc.2001.template), function(i) {
    template.comp.fx(year = inc.2001.template[[i]][[1]],
                     pm = inc.2001.template[[i]][[2]],
                     eco = inc.2001.template[[i]][[3]],
                     depth_bot = inc.2001.template[[i]][[4]],
                     dat = "inc")
  })
)

# 2001 bulk soil template
sra.2001 <- vector(mode = "list", length = length(unique(sra.2019.df$pro_name)))
names(sra.2001) <- unique(sra.2019.df$pro_name)

# 2019 bulk soil template
sra.2019 <- sra.2001

# inc templates for merging 14C data
sra.2019.inc <- vector(mode = "list", length = length(unique(sra.2019.inc.df$pro_name)))
names(sra.2019.inc) <- unique(sra.2019.inc.df$pro_name)
sra.2001.inc <- sra.2019.inc
# copies for reps of incubations
sra.2019.inc_L <- sra.2019.inc
names(sra.2019.inc_L) <- substr(names(sra.2019.inc_L), 1, 4)
# complete cases, convert type for calculating stocks later
# could calculate stocks now and then remove for the following steps where not needed

## 2001 summary data
soc.2001 <- data.frame(read_excel("../data/external/sra_ras_sum/sierra_data_summary_2020.xlsx",
                                  sheet = "2001_bulk_data"))

# create list; remove BS samples deeper than 30 cm
soc.2001.ls <- lapply(split(soc.2001, soc.2001$PMeco), function(df) {
  df <- type.convert(df[complete.cases(df), c("ID", "C.", "mass_kgm2", "PMeco", "pro_rep", "lyr_top", "lyr_bot")])
 return(df[which(df$lyr_bot < 36), ])
})

# Incubation samples combined 0-3 and 3-8 depth increments for BSrf and GRrf
# combine BSrf and GRrf initial depths
# function for calculating weighted average of first two depth increment C content
d1d2.fx <- function(df) {
  d1d2 <- data.frame(ID = paste(df$PMeco[1], df$pro_rep[1], df$lyr_top[1], df$lyr_bot[2], sep = "_"),
                     C. = sum(df$C.[1] * ((df$lyr_bot[1] - df$lyr_top[1]) / df$lyr_bot[2]), df$C.[2] * ((df$lyr_bot[2] - df$lyr_top[2]) / df$lyr_bot[2])),
                     mass_kgm2 = sum(df$mass_kgm2[1], df$mass_kgm2[2]),
                     PMeco = df$PMeco[1],
                     pro_rep = df$pro_rep[1],
                     lyr_top = df$lyr_top[1],
                     lyr_bot = df$lyr_bot[2])
  return(rbind(d1d2,
               df[3:nrow(df), ]))
}
# Run d1d2.fx for BSrf, GRrf
soc.2001.ls.inc <- soc.2001.ls 
soc.2001.ls.inc$GRrf <- bind_rows(lapply(split(soc.2001.ls$GRrf, soc.2001.ls$GRrf$pro_rep), d1d2.fx))
soc.2001.ls.inc$BSrf <- bind_rows(lapply(split(soc.2001.ls$BSrf, soc.2001.ls$BSrf$pro_rep), d1d2.fx))

# summarize inc
soc.2001.inc.sum <- data.frame(bind_rows(lapply(soc.2001.ls.inc, function(df) {
  df %>%
    mutate(ID2 = paste0(PMeco, "_", lyr_top, "-", lyr_bot)) %>%
    group_by(ID2, PMeco, lyr_top, lyr_bot) %>%
    summarize(c_pct_avg = mean(C.))
})))
save(soc.2001.inc.sum, file = "soc.2001.inc.sum.RData")

# calculate SOC stocks
soc.2001.ls <- lapply(soc.2001.ls, function(df) {
  df$lyr_soc_kgm2 <- df$C. * df$mass_kgm2 * 10^-2
  return(df)
})

# summarize [note that soc stocks are dropped]
soc.2001.sum <- data.frame(bind_rows(lapply(soc.2001.ls, function(df) {
  df %>%
    mutate(ID2 = paste0(PMeco, "_", lyr_top, "-", lyr_bot)) %>%
    group_by(ID2, PMeco, lyr_top, lyr_bot) %>%
    summarize(c_pct_avg = mean(C.))
})))

# 2019 data
sra.2019.cn.sum <- data.frame(
  bind_rows(unlist(elm_results_ls, recursive = FALSE)) %>%
  mutate(PMeco = sapply(strsplit(ID, "_"), "[", 2),
         depth = sapply(strsplit(ID, "_"), "[", 4)) %>%
  group_by(PMeco, depth) %>%
  summarize(across(c(C, N), .fns = mean))) %>%
  rename(c_pct_avg = C,
         n_pct_avg = N)
sra.2019.cn.sum$ID2 <- paste(sra.2019.cn.sum$PMeco, sra.2019.cn.sum$depth, sep = "_")
save(sra.2019.cn.sum, file = "sra.2019.cn.sum.RData")

Merge templates with 14C, C, and N data

Radiocarbon analyses for the 2001 samples were not run originally, but were completed on archived samples in 2020.

# Extract 14C data for 2001 samples
ams_results_ls_S01 <- ams_results_ls[grep("S01", names(ams_results_ls))]
for(i in seq_along(sra.2001)) {
  sra.2001[[i]] <- lapply(ams_results_ls_S01, function(ls) {
    lapply(ls, function(df) {
      if(any(grepl(names(sra.2001)[i], df$Probe))) {
       df[grep(names(sra.2001)[i], df$Probe), ] 
      }
    })
  })
  sra.2001[[i]] <- Filter(Negate(is.null), unlist(sra.2001[[i]], recursive = FALSE))
}
sra.2001 <- bind_rows(unlist(sra.2001, recursive = FALSE))

# create ID field, trim df, and add depths
sra.2001$ID <- unlist(strsplit(sra.2001$Probe, "_Sierra Nevada_2001"))
sra.2001 <- sra.2001[ , c("ID", "F14C", "err", "∆14C.(‰)", "err.(‰)")]
names(sra.2001) <- c("ID", "fm", "fm_err", "d14c", "d14c_err")
sra.2001$lyr_top <- as.numeric(ifelse(substr(sra.2001$ID, 9, 9) == "-",
                                      substr(sra.2001$ID, 8, 8),
                                      substr(sra.2001$ID, 8, 9)))
sra.2001$lyr_bot <- as.numeric(ifelse(substr(sra.2001$ID, 9, 9) == "-", 
                                      substr(sra.2001$ID, 10, nchar(sra.2001$ID)),
                                      substr(sra.2001$ID, 11, nchar(sra.2001$ID))))
sra.2001$pro_rep <- substr(sra.2001$ID, 6, 6)
sra.2001$PM <- factor(substr(sra.2001$ID, 1, 2))
sra.2001$ECO <- factor(substr(sra.2001$ID, 3, 4), levels = c("pp", "wf", "rf"))
sra.2001$pro_name <- substr(sra.2001$ID, 1, 6)
sra.2001$PMeco <- substr(sra.2001$ID, 1, 4)

# remove outlier ANpp sample
sra.2001 <- sra.2001[-which(sra.2001$ID == "ANpp_3_6-13"), ]

# make list by PMeco
sra.2001.ls <- split(sra.2001, sra.2001$PMeco)
# Extract 14C data for 2019 samples
ams_results_ls_S19 <- ams_results_ls[grep("soil-S19", names(ams_results_ls))]
for(i in seq_along(sra.2019)) {
  sra.2019[[i]] <- lapply(ams_results_ls_S19, function(ls) {
    lapply(ls, function(df) {
      if(any(grepl(names(sra.2019)[i], df$Probe))) {
       df[grep(names(sra.2019)[i], df$Probe), ] 
      }
    })
  })
  sra.2019[[i]] <- Filter(Negate(is.null), unlist(sra.2019[[i]], recursive = FALSE))
}
sra.2019 <- bind_rows(unlist(sra.2019, recursive = FALSE))

## merge w/ 2019 template
# rename cols in AMS tables
sra.2019 <- sra.2019[ , c("Probe", "F14C", "err", "∆14C.(‰)", "err.(‰)")]
names(sra.2019) <- c("ID", "fm", "fm_err", "d14c", "d14c_err")
# merge
sra.2019.ls <- lapply(split(sra.2019.df, sra.2019.df$lyr_name), function(df) {
  df <- merge(df, sra.2019[grep(df$lyr_name, sra.2019$ID), ])
  df$ID <- NULL
  df$PMeco <- paste0(df$PM, df$ECO)
  return(df)
})

# reshape list by PMeco
sra.2019.ls <- split(bind_rows(sra.2019.ls), bind_rows(sra.2019.ls)[["PMeco"]])
### Extract 14C data for incubation samples
## respired CO2, soil
# 2019
ams_results_ls_co2_S19 <- ams_results_ls[grep("co2-S19", names(ams_results_ls))]
for (i in seq_along(sra.2019.inc)) {
  sra.2019.inc[[i]] <- lapply(ams_results_ls_co2_S19, function(ls) {
    lapply(ls, function(df) {
      if (any(grepl(names(sra.2019.inc)[i], df$Probe))) {
        df[grep(names(sra.2019.inc)[i], df$Probe), ] 
      }
    })
  })
  sra.2019.inc[[i]] <- Filter(Negate(is.null), unlist(sra.2019.inc[[i]], recursive = FALSE))
}
sra.2019.inc <- type.convert(
  bind_rows(
    lapply(unlist(sra.2019.inc, recursive = FALSE), 
           function(x) x %>% mutate_all(as.character))),
  as.is = TRUE)
sra.2019.inc <- sra.2019.inc[-which(is.na(sra.2019.inc$F14C)), ]

# 2001
ams_results_ls_co2_S01 <- ams_results_ls[grep("co2-S01", names(ams_results_ls))]
# remove questionable/duplicate samples
# ANrf_comp_11-32_2001_a (analyzed twice; both anomously low compared to rep and rest of data)
ams_results_ls_co2_S01$`ams_jena_results-co2-S01_2020-12-11`$`Beem-Miller_22.xlsx` <- ams_results_ls_co2_S01$`ams_jena_results-co2-S01_2020-12-11`$`Beem-Miller_22.xlsx`[-grep("ANrf_comp_11-32_2001_a", ams_results_ls_co2_S01$`ams_jena_results-co2-S01_2020-12-11`$`Beem-Miller_22.xlsx`$Probe), ]
ams_results_ls_co2_S01$`ams_jena_results-co2-S01_2020-12-16`$`14C_SierraNevada_Inc_2001_3_results.xlsx` <- ams_results_ls_co2_S01$`ams_jena_results-co2-S01_2020-12-16`$`14C_SierraNevada_Inc_2001_3_results.xlsx`[-grep("ANrf_comp_11-32_2001_a", ams_results_ls_co2_S01$`ams_jena_results-co2-S01_2020-12-16`$`14C_SierraNevada_Inc_2001_3_results.xlsx`$Probe), ]
# from original analysis of samples extracted online 11-Dec-2020 (see readme for notes)
ams_results_ls_co2_S01$`ams_jena_results-co2-S01_2020-12-11`$`Beem-Miller_23.xlsx` <- ams_results_ls_co2_S01$`ams_jena_results-co2-S01_2020-12-11`$`Beem-Miller_23.xlsx`[-grep("GRwf_comp_13-28_2001_a_11", ams_results_ls_co2_S01$`ams_jena_results-co2-S01_2021-01-26`$`14C_SierraNevada_Inc_2001_2_results.xlsx`$Probe), ]
# from reanalysis of samples extracted online 11-Dec-2020 (see readme for notes)
# GRrf_comp_8-27_2001_a_5, GRrf_comp_8-27_2001_b_6, GRpp_comp_15-27_2001_b_18 
ams_results_ls_co2_S01$`ams_jena_results-co2-S01_2021-01-26`$`14C_SierraNevada_Inc_2001_2_results.xlsx` <- ams_results_ls_co2_S01$`ams_jena_results-co2-S01_2021-01-26`$`14C_SierraNevada_Inc_2001_2_results.xlsx`[c(
  grep("GRrf_comp_8-27_2001_a_5", ams_results_ls_co2_S01$`ams_jena_results-co2-S01_2021-01-26`$`14C_SierraNevada_Inc_2001_2_results.xlsx`$Probe),
  grep("GRwf_comp_13-28_2001_b_12", ams_results_ls_co2_S01$`ams_jena_results-co2-S01_2021-01-26`$`14C_SierraNevada_Inc_2001_2_results.xlsx`$Probe)), ]

# create template for extracting data
sra.2001.inc <- vector(mode = "list", length = length(unique(sra.2019.inc.df$pro_name)))
names(sra.2001.inc) <- unique(sra.2019.inc.df$pro_name)
# merge with 14C data
for (i in seq_along(sra.2001.inc)) {
  sra.2001.inc[[i]] <- lapply(ams_results_ls_co2_S01, function(ls) {
    lapply(ls, function(df) {
      if (any(grepl(names(sra.2001.inc)[i], df$Probe))) {
        df[grep(names(sra.2001.inc)[i], df$Probe), ] 
      }
    })
  })
  sra.2001.inc[[i]] <- Filter(Negate(is.null), unlist(sra.2001.inc[[i]], recursive = FALSE))
}
sra.2001.inc <- type.convert(
  bind_rows(
    lapply(unlist(sra.2001.inc, recursive = FALSE), 
           function(x) x %>% mutate_all(as.character))),
  as.is = TRUE)
sra.2001.inc <- sra.2001.inc[-which(is.na(sra.2001.inc$F14C)), ]

# respired CO2, litter
ams_results_ls_co2_L19 <- ams_results_ls[grep("co2-L19", names(ams_results_ls))]
for(i in seq_along(sra.2019.inc_L)) {
  sra.2019.inc_L[[i]] <- lapply(ams_results_ls_co2_L19, function(ls) {
    lapply(ls, function(df) {
      if(any(grepl(names(sra.2019.inc_L)[i], df$Probe))) {
       df[grep(names(sra.2019.inc_L)[i], df$Probe), ] 
      }
    })
  })
  sra.2019.inc_L[[i]] <- Filter(Negate(is.null), unlist(sra.2019.inc_L[[i]], recursive = FALSE))
}
sra.2019.inc_L <- bind_rows(unlist(sra.2019.inc_L, recursive = FALSE))

## merge w/ templates [why do I do this twice?]
# rename cols in AMS tables
# soil CO2
sra.2019.inc <- sra.2019.inc[ , c("Probe", "F14C", "err", "∆14C.(‰)", "err.(‰)")]
names(sra.2019.inc) <- c("ID", "fm", "fm_err", "d14c", "d14c_err")
sra.2001.inc <- sra.2001.inc[ , c("Probe", "F14C", "err", "∆14C.(‰)", "err.(‰)")]
names(sra.2001.inc) <- c("ID", "fm", "fm_err", "d14c", "d14c_err")
# merge
# 2019
sra.2019.inc.ls <- bind_rows(
  lapply(split(sra.2019.inc.df, sra.2019.inc.df$lyr_name), function(df) {
    df <- merge(df, sra.2019.inc[grep(df$lyr_name, sra.2019.inc$ID), ])
    df$ID <- NULL
    df$PMeco <- paste0(df$PM, df$ECO)
    return(df)
  })
)
sra.2019.inc.ls <- split(sra.2019.inc.ls, sra.2019.inc.ls$PMeco)
# 2001
sra.2001.inc.ls <- bind_rows(
  lapply(split(sra.2001.inc.df, sra.2001.inc.df$lyr_name), function(df) {
    df <- merge(df, sra.2001.inc[grep(df$lyr_name, sra.2001.inc$ID), ])
    df$ID <- NULL
    df$PMeco <- paste0(df$PM, df$ECO)
    return(df)
  })
)
sra.2001.inc.ls <- split(sra.2001.inc.ls, sra.2001.inc.ls$PMeco)

# save inc list
save(sra.2001.inc.ls, file = "sra.2001.inc.ls.RData")

# litter CO2
sra.2019.inc_L <- sra.2019.inc_L[ , c("Probe", "F14C", "err", "∆14C.(‰)", "err.(‰)")]
names(sra.2019.inc_L) <- c("ID", "fm", "fm_err", "d14c", "d14c_err")
sra.2019.inc_L$ID <- substr(substring(sra.2019.inc_L$ID, 
                                      regexpr("_", sra.2019.inc_L$ID) + 1, 
                                      nchar(sra.2019.inc_L$ID)),
                            1, 8)
sra.2019.inc.df_L <- data.frame(Year = rep(2019, 18),
                                rep = rep(c(1, 2), 9),
                                PM = rep(c("AN", "BS", "GR"), each = 6),
                                eco = rep(c("pp", "wf", "rf"), each = 2, times = 3))
sra.2019.inc.df_L$PMeco <- paste0(sra.2019.inc.df_L$PM, sra.2019.inc.df_L$eco)
sra.2019.inc.df_L$ID <- paste0(sra.2019.inc.df_L$PM, sra.2019.inc.df_L$eco, "-L_", sra.2019.inc.df_L$rep)
# add dry wts and litter depth
sra.2019.L <- read.csv("../data/derived/lab_jena_litter/Litter_2019_2021-01-27.csv")
sra.2019.inc.df_L <- merge(sra.2019.inc.df_L, sra.2019.L[ , c("PMeco", "lyr_top", "lyr_bot")], all.x = TRUE)
# merge
sra.2019.inc_L.df <- bind_rows(
  lapply(split(sra.2019.inc_L, sra.2019.inc_L$ID), function(df) {
    df <- merge(df, sra.2019.inc.df_L, by = "ID")
    df$ID <- NULL
    return(df)
  })
)
sra.2019.inc_L.ls <- split(sra.2019.inc_L.df, sra.2019.inc_L.df$PMeco)
# fm and d14c conversion functions
lambda <- 1/8267 # = 1/(true mean life of 14C)
calc_fm <- function(d14c, obs_date_y) {
  ((d14c/1000) + 1)/exp(lambda * (1950 - obs_date_y))
}
calc_14c <- function(fm, obs_date_y) {
  (fm * exp(lambda * (1950 - obs_date_y)) - 1) * 1000
}

# calc atm in 2001, 2009, 2019
Datm <- rbind(graven, future14C)
atm.d14.2001 <- Datm[Datm$Date == 2001.5, "NHc14"]
atm.fm.2001 <- calc_fm(atm.d14.2001, 2001)
atm.d14.2009 <- Datm[Datm$Date == 2009.5, "NHc14"]
atm.fm.2009 <- calc_fm(atm.d14.2009, 2009)
atm.d14.2019 <- Datm[Datm$Date == 2019.5, "NHc14"]
atm.fm.2019 <- calc_fm(atm.d14.2019, 2019)
fig.n <- fig.n + 1
# summarize litter inc data
sra.2019.inc_L.sum <- sra.2019.inc_L.df %>%
  mutate(eco = factor(ifelse(eco == "pp", "warm",
                             ifelse(eco == "wf", "cool", "cold")),
                      levels = c("warm", "cool", "cold")),
         pm = factor(ifelse(PM == "AN", "andesite",
                     ifelse(PM == "BS", "basalt", "granite"))),
         Year = factor("2019")) %>%
  group_by(Year, PMeco, pm, eco, lyr_top, lyr_bot) %>%
  summarize(d14c_mean = mean(d14c),
            d14c_u = max(d14c),
            d14c_l = min(d14c),
            fm_mean = mean(fm),
            fm_u = max(fm),
            fm_l = min(fm))

# plot as cols by climate
sra.2019.inc_L.sum %>%
  mutate(MAT = factor(eco, levels = c("warm", "cool", "cold"), labels = c("10-13", "8-10", "5-6"))) %>%
  ggplot(., aes(MAT, d14c_mean, fill = pm)) +
  geom_hline(yintercept = 0) +
  geom_hline(yintercept = atm.d14.2019, linetype = "dashed") +
  geom_col(position = "dodge2") +
  geom_errorbar(aes(ymax = d14c_u, ymin = d14c_l, color = pm), 
                position = position_dodge2(width = .5, padding = .5)) +
  scale_fill_manual(name = "Parent material",
                    values = c("andesite" = "blue", 
                               "basalt" = "red", 
                               "granite" = "darkgray")) +
  scale_color_manual(name = "Parent material",
                     values = c("andesite" = "blue", 
                                "basalt" = "red", 
                                "granite" = "darkgray")) +
  coord_flip() +
  ylab(expression(Delta*''^14*'C (‰)')) +
  xlab(expression("MAT ("*~degree*C*")")) +
  theme_bw() +
  theme(panel.grid = element_blank())


# plot as points with depth
sra.2019.inc_L.sum %>%
  ggplot(., aes(d14c_mean, lyr_top, color = pm)) +
  geom_vline(xintercept = 0) +
  geom_hline(yintercept = 0) +
  geom_vline(xintercept = atm.d14.2019, linetype = "dashed") +
  geom_point(size = 3) +
  geom_errorbarh(aes(xmax = d14c_u, xmin = d14c_l), height = 1) +
  scale_y_reverse() +
  scale_color_manual(name = "Parent material",
                     values = c("andesite" = "blue", 
                                "basalt" = "red", 
                                "granite" = "darkgray")) +
  facet_grid(rows = vars(eco)) +
  xlab(expression(Delta*''^14*'C (‰)')) +
  ylab("Depth (cm)") +
  theme_bw() +
  theme(panel.grid = element_blank())

Fig. 16. Litter incubation \(\Delta\)14C-CO2 (2019)

Caption: Mean \(\Delta\)14C-CO2 for each site. Error bars show min and max of duplicate incubation samples. a) Data shown by site, without litter depth, b) Data shown by depth of litter layer, binned by climate zone.

pro.plot <- function(df, maxDepth, min14C, rep) {
  ggplot(df, aes(d14c, lyr_bot, color = PM, shape = ECO, group = rep)) +
    geom_vline(xintercept = 0) +
    geom_hline(yintercept = 0) +
    geom_point(size = 3) +
    geom_path() +
    scale_y_reverse(limits = c(maxDepth, 0)) +
    scale_x_continuous(limits = c(min14C, 180)) +
    scale_color_manual(name = "parent material",
                       labels = c("AN" = "andesite",
                                  "BS" = "basalt",
                                  "GR" = "granite"),
                       values = c("AN" = "blue", 
                                  "BS" = "red", 
                                  "GR" = "darkgray")) +
    scale_shape_manual(name = "ecosystem",
                       labels = c("pp" = expression(italic("P. ponderosa")),
                                  "rf" = expression(italic("A. magnifica")),
                                  "wf" = expression(italic("A. concolor"))),
                       values = c("pp" = 15, 
                                  "rf" = 16, 
                                  "wf" = 17)) +
    xlab(expression(Delta*''^14*'C (‰)')) +
    ylab("Depth (cm)") +
    theme_bw() +
    theme(panel.grid.minor = element_blank())
}
# lapply(sra.2001.ls, function(df) pro.plot(df, max(df$lyr_bot), min(df$d14c), df$pro_rep))
# lapply(sra.2019.ls, function(df) pro.plot(df, max(df$lyr_bot), min(df$d14c), df$pro_rep))
# lapply(sra.2019.inc.ls, function(df) pro.plot(df, max(df$lyr_bot), min(df$d14c), NA))

2001 mean radiocarbon profiles

# combine reps
sra.2001.sum.ls  <- lapply(sra.2001.ls, function(df) {
  df <- data.frame(df %>%
                     filter(lyr_bot <= 40) %>%
                     mutate(lyr_top_ch = as.character(lyr_top),
                            lyr_bot_ch = as.character(lyr_bot)) %>%
                     select(PM, ECO, PMeco, fm, d14c, lyr_top_ch, lyr_bot_ch) %>%
                     group_by(PM, ECO, PMeco, lyr_top_ch, lyr_bot_ch) %>%
                     summarize_all(list(mean = mean, sd = sd), na.rm = TRUE))
  names(df) <- c("PM", "ECO", "PMeco", "lyr_top", "lyr_bot", "fm", "d14c", "fm_sd", "d14c_sd")
  df$lyr_top <- as.numeric(df$lyr_top)
  df$lyr_bot <- as.numeric(df$lyr_bot)
  df$d14c_u <- df$d14c + df$d14c_sd
  df$d14c_l <- df$d14c - df$d14c_sd
  return(df[order(df$lyr_bot), ])
})
sra.01.sum <- bind_rows(sra.2001.sum.ls) %>%
  mutate(eco = factor(ifelse(ECO == "pp", "warm",
                      ifelse(ECO == "wf", "cool", "cold")),
                      levels = c("warm", "cool", "cold")),
         pm = ifelse(PM == "AN", "andesite",
                     ifelse(PM == "BS", "basalt", "granite")))

# plot
fig.n <- fig.n + 1
sra.01.sum %>%
  ggplot(., aes(d14c, lyr_bot, color = pm, shape = eco, group = PMeco)) +
  geom_vline(xintercept = atm.d14.2001) +
  geom_hline(yintercept = 0) +
  geom_point(size = 3) +
  geom_errorbarh(
    aes(xmin = d14c_l, 
        xmax = d14c_u,
        color = pm), 
    height = 1.5) +
  geom_path() +
  scale_y_reverse(limits = c(40, 0)) +
  scale_x_continuous(limits = c(-100, 180)) +    
  scale_color_manual(name = "parent material",
                     values = c("andesite" = "blue", 
                                "basalt" = "red", 
                                "granite" = "darkgray")) +
  scale_shape_manual(name = "ecosystem",
                     values = c("warm" = 15, 
                                "cool" = 16, 
                                "cold" = 17)) +
  xlab(expression(Delta*''^14*'C (‰)')) +
  ylab("Depth (cm)") +
  facet_grid(rows = vars(eco), cols = vars(pm)) +
  theme_bw() +
  theme(panel.grid.minor = element_blank())

Fig. 16. Mean profile \(\Delta\)14C for 2001 samples

Caption: Mean \(\Delta\)14C by depth for each site in 2001. Error bars show ±1 standard deviation, solid vertical line shows \(\Delta\)14C of the atmosphere in the year of sampling.

2009 radiocarbon profiles

# 2009 summary data (from C. Rasmussen)
ras18.sum <- read_excel(
  "../data/external/sra_ras_sum/sierra_data_summary_2020.xlsx",
  sheet = "Data_Summary_2018_paper")

# remove empty data rows
ras18.sum <- ras18.sum[-which(is.na(ras18.sum$`Sample ID`)), ]

# summarize 09 data
sra.09.sum <- ras18.sum %>%
  mutate(
    ECO = ifelse(Biome == "PP", "pp", ifelse(Biome == "WF", "wf", "rf")),
    PM = ifelse(Parent_Material == "Andesite", "AN", ifelse(Parent_Material == "Basalt", "BS", "GR")),
    eco = factor(ifelse(ECO == "pp", "warm", ifelse(ECO == "wf", "cool", "cold")),
                 levels = c("warm", "cool", "cold")),
    pm = paste0(tolower(substr(Parent_Material, 1, 1)), 
                substr(Parent_Material, 2, nchar(Parent_Material))),
    mass_kgm2 = BD_g_cm_3 * Soil_finefraction * (`bottom mineral` - `top mineral`) * 10) %>%
  mutate(PMeco = paste0(PM, ECO)) %>%
  rename(d14c = "Δ14C",
         lyr_bot = "bottom mineral",
         lyr_top = "top mineral")
sra.2009.ls <- lapply(split(sra.09.sum, sra.09.sum$PMeco), function(df) {
  df$lyr_fraction_modern <- calc_fm(df$d14c, 2009)
  return(data.frame(df))
})

# 2009 bulk C data
ras18.blkC <- as.data.frame(read_excel(
  "../data/external/sra_ras_sum/sierra_data_summary_2020.xlsx",
  sheet = "2009_bulk_data"))

# Add PM, ECO, mass_kgm2 vars
ras18.blkC$ECO <- ifelse(ras18.blkC$Biome == "PP", "pp", ifelse(ras18.blkC$Biome == "RF", "rf", "wf"))
ras18.blkC$PMeco <- paste0(ras18.blkC$PM, ras18.blkC$ECO)
ras18.blkC$mass_kgm2 <- ras18.blkC$Thickness_cm * ras18.blkC$BD_g_cm_3 * ras18.blkC$Soil_finefraction * 10

# Calculate SOC stocks
ras18.blkC$lyr_soc <- ras18.blkC$Thickness_cm * ras18.blkC$BD_g_cm_3 * ras18.blkC$Soil_finefraction * ras18.blkC$C_pct * 10^-1

# Calculate cmtv SOC stocks
ras18.blkC$lyr_soc_cmtv <- unlist(lapply(split(ras18.blkC, ras18.blkC$pro_name), function(x) {
  x$lyr_soc_cmtv <- NA
  for (i in seq(nrow(x))) {
    if (i == 1) {
      x$lyr_soc_cmtv[i] <- x$lyr_soc[i]
    } else {
      x$lyr_soc_cmtv[i] <- x$lyr_soc[i] + x$lyr_soc_cmtv[i - 1]
    }
  }
  return(x$lyr_soc_cmtv)
}))
# LOOCV function, fit = lm mod
loocv <- function (fit) {
  h <- lm.influence(fit)$h
  mean((residuals(fit) / (1-h))^2)
}

# test function for predicting BD as function of PM, ECO, and C content
bd.mod <- lm(BD_g_cm_3 ~ PM * ECO + PM * C_pct + `bottom mineral`, ras18.blkC)
bd.pred <- predict.lm(bd.mod, ras18.blkC, interval = "predict", pred.var = loocv(bd.mod))
bd.err.df <- ras18.blkC
bd.err.df$BD_pred <- bd.pred[ , 1]
bd.err.df$BD_l <- bd.pred[ , 2]
bd.err.df$BD_u <- bd.pred[ , 3]

# plot
ggplot(bd.err.df, aes(BD_g_cm_3, BD_pred)) +
  geom_ribbon(aes(ymin = BD_l, ymax = BD_u), fill = "lightgray") +
  geom_smooth(method = "lm", formula = y ~ x, se = FALSE, color = "black") +
  geom_point(aes(color = PM, shape = ECO, size = `bottom mineral`/10)) +
  scale_color_manual(name = "Parent material",
                     values = c("AN" = andesite,
                                "BS" = basalt,
                                "GR" = granite)) +
  theme_bw() +
  theme(panel.grid = element_blank())

# plot
fig.n <- fig.n + 1
sra.09.sum %>%
  ggplot(., aes(d14c, lyr_bot, color = pm, shape = eco, group = PMeco)) +
  geom_vline(xintercept = atm.d14.2009) +
  geom_hline(yintercept = 0) +
  geom_point(size = 3) +
  geom_path(linetype = "dashed") +
  scale_y_reverse() +
  scale_x_continuous(limits = c(-100, 180)) +    
  scale_color_manual(name = "parent material",
                     values = c("andesite" = "blue", 
                                "basalt" = "red", 
                                "granite" = "darkgray")) +
  scale_shape_manual(name = "ecosystem",
                     values = c("warm" = 0, 
                                "cool" = 1, 
                                "cold" = 2)) +
  xlab(expression(Delta*''^14*'C (‰)')) +
  ylab("Depth (cm)") +
  facet_grid(rows = vars(eco), cols = vars(pm)) +
  theme_bw() +
  theme(panel.grid.minor = element_blank())

Fig. 16. Profile \(\Delta\)14C for 2009 samples

Caption: Profile \(\Delta\)14C by depth for each site in 2009. Solid vertical line shows \(\Delta\)14C of the atmosphere in the year of sampling. Error bars not shown as only a single replicate profile was analyzed per site.

2019 mean radiocarbon profiles

# combine reps
sra.2019.sum.ls  <- lapply(sra.2019.ls, function(df) {
  df <- data.frame(df %>%
                     mutate(lyr_top_ch = as.character(lyr_top),
                            lyr_bot_ch = as.character(lyr_bot)) %>%
                     select(PM, ECO, PMeco, fm, d14c, lyr_top_ch, lyr_bot_ch) %>%
                     group_by(PM, ECO, PMeco, lyr_top_ch, lyr_bot_ch) %>%
                     summarize_all(list(mean = mean, sd = sd), na.rm = TRUE))
  names(df) <- c("PM", "ECO", "PMeco", "lyr_top", "lyr_bot", "fm", "d14c", "fm_sd", "d14c_sd")
  df$lyr_top <- as.numeric(df$lyr_top)
  df$lyr_bot <- as.numeric(df$lyr_bot)
  df$d14c_u <- df$d14c + df$d14c_sd
  df$d14c_l <- df$d14c - df$d14c_sd
  return(df)
})
sra.19.sum <- bind_rows(sra.2019.sum.ls) %>%
  mutate(eco = factor(ifelse(ECO == "pp", "warm",
                      ifelse(ECO == "wf", "cool", "cold")),
                      levels = c("warm", "cool", "cold")),
         pm = ifelse(PM == "AN", "andesite",
                     ifelse(PM == "BS", "basalt", "granite"))) 

# plot
fig.n <- fig.n + 1
sra.19.sum %>%
  ggplot(., aes(d14c, lyr_bot, color = pm, shape = eco, group = PMeco)) +
  geom_vline(xintercept = atm.d14.2019) +
  geom_hline(yintercept = 0) +
  geom_point(size = 2.7) +
  geom_errorbarh(
    aes(xmin = d14c_l, 
        xmax = d14c_u,
        color = pm), 
    height = 1.5) +
  geom_path() +
  scale_y_reverse(limits = c(max(sra.19.sum$lyr_bot), 0)) +
  scale_x_continuous(limits = c(min(sra.19.sum$d14c), 180)) +    
  scale_color_manual(name = "parent material",
                     values = c("andesite" = "blue", 
                                "basalt" = "red", 
                                "granite" = "darkgray")) +
  scale_shape_manual(name = "ecosystem",
                     values = c("warm" = 15, 
                                "cool" = 16, 
                                "cold" = 17)) +
  xlab(expression(Delta*''^14*'C (‰)')) +
  ylab("Depth (cm)") +
  facet_grid(rows = vars(eco), cols = vars(pm)) +
  theme_bw() +
  theme(panel.grid.minor = element_blank())

Fig. 16. Mean profile \(\Delta\)14C for 2019 samples

Caption: Mean \(\Delta\)14C by depth for each site in 2019. Error bars show ±1 standard deviation, solid vertical line shows \(\Delta\)14C of the atmosphere in the year of sampling.

Change in \(\Delta\)14C over time between 2001 and 2019

# combine '01 and '19 data for plotting
sra.01.sum$Year <- 2001
sra.19.sum$Year <- 2019

sra.01.19.sum <- rbind(sra.01.sum, sra.19.sum)
sra.01.19.sum$Year <- as.factor(sra.01.19.sum$Year)

fig.n <- fig.n + 1
sra.01.19.sum %>%
  mutate(PMeco_year = paste0(PMeco, Year),
         ecoYear = paste0(ECO, Year),
         ecoYear2 = ifelse(ecoYear == "pp2001", "warm (2001)",
                           ifelse(ecoYear == "pp2019", "warm (2019)",
                                  ifelse(ecoYear == "wf2001", "cool (2001)",
                                         ifelse(ecoYear == "wf2019", "cool (2019)",
                                                ifelse(ecoYear == "rf2001", "cold (2001)", "cold (2019)")))))) %>%
  ggplot(., aes(d14c, lyr_bot, color = pm, shape = ecoYear2, group = PMeco_year)) +
  geom_vline(xintercept = atm.d14.2001) +
  geom_vline(xintercept = atm.d14.2019, linetype = "dashed") +
  geom_hline(yintercept = 0) +
  geom_point(size = 3) +
  geom_errorbarh(
    aes(xmin = d14c_l, 
        xmax = d14c_u,
        color = pm), 
    height = 1.5) +
  geom_path(aes(linetype = Year)) +
  scale_y_reverse(limits = c(41, 0)) +
  scale_color_manual(name = "parent material",
                     values = c("andesite" = "blue", 
                                "basalt" = "red", 
                                "granite" = "darkgray")) +
  scale_shape_manual(name = "Ecosystem (year)",
                     values = c("warm (2001)" = 15, 
                                "cool (2001)" = 16, 
                                "cold (2001)" = 17,
                                "warm (2019)" = 0, 
                                "cool (2019)" = 1, 
                                "cold (2019)" = 2)) +
  xlab(expression(Delta*''^14*'C (‰)')) +
  ylab("Depth (cm)") +
  facet_grid(rows = vars(eco), cols = vars(pm)) +
  theme_bw() +
  theme(panel.grid.minor = element_blank())

Fig. 16. Mean profile \(\Delta\)14C for 2001 and 2019 samples

Caption: Mean \(\Delta\)14C by depth for each site in 2001 and 2019. Error bars show ±1 standard deviation. Vertical lines show \(\Delta\)14C of the atmosphere in 2001 (solid) and 2019 (dashed).

Incubation \(\Delta\)14C-CO2

## 2019
sra.2019.inc.df <- bind_rows(sra.2019.inc.ls)
# add litter inc data and summarize
sra.2019.inc.sum.df <- data.frame(rbind(
  sra.2019.inc_L.sum,
  sra.2019.inc.df %>%
    mutate(eco = factor(ifelse(ECO == "pp", "warm",
                             ifelse(ECO == "wf", "cool", "cold")),
                      levels = c("warm", "cool", "cold")),
           pm = factor(ifelse(PM == "AN", "andesite",
                     ifelse(PM == "BS", "basalt", "granite"))),
           # remove GRrf 10-20 "a" point
           d14c = replace(d14c, which(d14c < -300), NA),
           Year = factor(Year)) %>%
  group_by(Year, PMeco, pm, eco, lyr_bot, lyr_top) %>%
  summarize(d14c_mean = mean(d14c, na.rm = TRUE),
            d14c_l = min(d14c, na.rm = TRUE),
            d14c_u = max(d14c, na.rm = TRUE),
            fm_mean = mean(fm),
            fm_l = min(fm),
            fm_u = max(fm))))
sra.2019.inc.sum.ls <- split(sra.2019.inc.sum.df, sra.2019.inc.sum.df$PMeco)

# 2001
sra.2001.inc.df <- bind_rows(sra.2001.inc.ls)
sra.2001.inc.sum.df <- data.frame(
  sra.2001.inc.df %>%
    mutate(eco = factor(ifelse(ECO == "pp", "warm",
                               ifelse(ECO == "wf", "cool", "cold")),
                        levels = c("warm", "cool", "cold")),
           pm = factor(ifelse(PM == "AN", "andesite",
                       ifelse(PM == "BS", "basalt", "granite"))),
           Year = factor(Year)) %>%
    group_by(Year, PMeco, pm, eco, lyr_bot, lyr_top) %>%
    summarize(d14c_mean = mean(d14c),
              d14c_l = min(d14c),
              d14c_u = max(d14c),
              fm_mean = mean(fm),
              fm_l = min(fm),
              fm_u = max(fm))
)
sra.2001.inc.sum.ls <- split(sra.2001.inc.sum.df, sra.2001.inc.sum.df$PMeco)
sra.2001.inc.sum.df <- sra.2001.inc.sum.df[ , !(names(sra.2001.inc.sum.df) %in% c("fm_mean", "fm_l", "fm_u", "lyr_top", "PMeco"))]
# 2019
fig.n <- fig.n + 1
sra.2019.inc.sum.df[order(sra.2019.inc.sum.df$lyr_bot), ] %>%
  ggplot(., aes(d14c_mean, lyr_bot, color = pm, shape = eco)) +
  geom_vline(xintercept = atm.d14.2019, linetype = "dashed") +
  geom_hline(yintercept = 0) +
  geom_point(size = 3) +
  geom_errorbarh(
    aes(xmin = d14c_l,
        xmax = d14c_u,
        color = pm),
    height = 1.5) +
  geom_path(linetype = "dashed") +
  scale_y_reverse() +
  scale_color_manual(name = "Parent material",
                     values = c("andesite" = "blue", 
                                "basalt" = "red", 
                                "granite" = "darkgray")) +
  scale_shape_manual(name = "Ecosystem",
                     values = c("warm" = 0, 
                                "cool" = 1, 
                                "cold" = 2)) +
  xlab(expression('Incubation '*Delta*''^14*'C-CO'[2]*' (‰)')) +
  ylab("Depth (cm)") +
  facet_grid(rows = vars(eco)) +
  theme_bw() +
  theme(panel.grid.minor = element_blank())

Fig. 16. \(\Delta\)14C-CO2 of 2019 bulk soil incubations

Caption: \(\Delta\)14CO2 by depth for each site in 2019. One rep from GRrf 10-20 (the 10-20 cm increment sample from the cold granite site) is strongly depleted relative to the other rep: \(\Delta\)14C-CO2 = -210.1. The highly depleted sample has been excluded for display reasons.

# plot 2001 data
fig.n <- fig.n + 1
sra.2001.inc.sum.df %>%
  ggplot(., aes(d14c_mean, lyr_bot, color = pm, shape = eco)) +
  geom_vline(xintercept = atm.d14.2001) +
  geom_hline(yintercept = 0) +
  geom_point(size = 3) +
  geom_errorbarh(
    aes(xmin = d14c_l,
        xmax = d14c_u,
        color = pm),
    height = 1.5) +
  geom_path() +
  scale_y_reverse() +
  scale_color_manual(name = "Parent material",
                     values = c("andesite" = "blue",
                                "basalt" = "red",
                                "granite" = "darkgray")) +
  scale_shape_manual(name = "Ecosystem",
                     values = c("warm" = 15,
                                "cool" = 16,
                                "cold" = 17)) +
  scale_x_continuous(limits = c(-70, 190)) +
  xlab(expression('Incubation '*Delta*''^14*'C-CO'[2]*' (‰)')) +
  ylab("Depth (cm)") +
  facet_grid(rows = vars(eco)) +
  theme_bw() +
  theme(panel.grid.minor = element_blank())

Fig. 16. \(\Delta\)14C-CO2 of 2001 bulk soil incubations

Caption: \(\Delta\)14CO2 by depth for each site in 2001. Note that some sites only have two depth increments. Similar to the 2019 dataset, one of the GRrf reps from the deepest depth increment was strongly depleted: \(\Delta\)14C-CO2 = -469.1. Both points have been excluded for display reasons.

# plot together
sra.inc.all <- rbind(sra.2001.inc.sum.df, 
                     sra.2019.inc.sum.df[ , names(sra.2019.inc.sum.df) %in% names(sra.2001.inc.sum.df)])
save(sra.inc.all, file = "sra.inc.all.RData")

fig.n <- fig.n + 1 
sra.inc.all %>%
  filter(lyr_bot > 0) %>%
  mutate(PMeco_year = paste0(pm, eco, Year),
         ecoYear = paste0(eco, " (", Year, ")")) %>%
  ggplot(., aes(d14c_mean, lyr_bot, color = pm, shape = ecoYear, group = PMeco_year)) +
  geom_vline(xintercept = atm.d14.2001) +
  geom_vline(xintercept = atm.d14.2019, linetype = "dashed") +
  geom_hline(yintercept = 0) +
  geom_point(size = 3) +
  geom_errorbarh(
    aes(xmin = d14c_l, 
        xmax = d14c_u,
        color = pm), 
    height = 1.5) +
  geom_path(aes(linetype = Year)) +
  scale_y_reverse(limits = c(41, 0)) +
  scale_color_manual(name = "parent material",
                     values = c("andesite" = "blue", 
                                "basalt" = "red", 
                                "granite" = "darkgray")) +
  scale_shape_manual(name = "Ecosystem (year)",
                     values = c("warm (2001)" = 15, 
                                "cool (2001)" = 16, 
                                "cold (2001)" = 17,
                                "warm (2019)" = 0, 
                                "cool (2019)" = 1, 
                                "cold (2019)" = 2)) +
  scale_x_continuous(limits = c(-70, 190)) +
  xlab(expression(Delta*''^14*'C (‰)')) +
  ylab("Depth (cm)") +
  facet_grid(rows = vars(eco), cols = vars(pm)) +
  theme_bw() +
  theme(panel.grid.minor = element_blank())

Fig. 16. \(\Delta\)14C-CO2 of 2001 and 2019 bulk soil incubations

Caption: \(\Delta\)14CO2 by depth for each site in 2001 and 2019. Different depth increments were sampled in 2001 and 2019. Points are the mean of laboratory duplicates; error bars are the measured values of each duplicate. Granite/cold point exlcuded for display reasons as it is strongly depleted.

Incubation vs. bulk soil \(\Delta\)14C

# bind rows of inc list
sra.19.inc <- sra.2019.inc.sum.df
sra.19.inc$Type <- "inc"

# 2001
sra.01.inc <- sra.2001.inc.sum.df
sra.01.inc$Type <- "inc"

# rbind bulk data
sra.19.bulk <- sra.19.sum[which(sra.19.sum$lyr_bot < 31), c("Year", "PM", "ECO", "lyr_bot","d14c", "d14c_l", "d14c_u")]
names(sra.19.bulk)[which(names(sra.19.bulk) == "d14c")] <- "d14c_mean"
sra.19.bulk$Type <- "bulk"
sra.19.bulk <- sra.19.bulk %>%
  mutate(pm = factor(ifelse(PM == "AN", "andesite",
                            ifelse(PM == "BS", "basalt", "granite"))),
         eco = factor(ifelse(ECO == "pp", "warm",
                             ifelse(ECO == "wf", "cool", "cold")),
                      levels = c("warm", "cool", "cold")),
         PM = NULL,
         ECO = NULL)
sra.19.inc.blk <- rbind(sra.19.bulk, sra.19.inc[ , names(sra.19.inc) %in% names(sra.19.bulk)])
save(sra.19.inc.blk, file = "sra.19.inc.blk.RData")

# 2001
# Need to calculate weighted average of radiocarbon values and stocks for combined inc depths 
# 1) add SOC stocks to duplicate sra.2001.ls obj
sra.2001.ls2 <- sra.2001.ls
for(i in seq_along(sra.2001.ls2)) {
  ix <- match(sra.2001.ls2[[i]][["ID"]], soc.2001.ls[[i]][["ID"]])
  sra.2001.ls2[[i]]["lyr_soc_kgm2"] <- soc.2001.ls[[i]][ix, "lyr_soc_kgm2"]
}
# 2) weighted average fx
d1d2.14c.fx <- function(df) {
  sum_soc <- sum(df[1:2, "lyr_soc_kgm2"])
  wt1 <- df$lyr_soc_kgm2[1] / sum_soc
  wt2 <- df$lyr_soc_kgm2[2] / sum_soc
  d1d2 <- df[1, ]
  d1d2$ID = paste(df$PMeco[1], df$pro_rep[1], df$lyr_top[1], df$lyr_bot[2], sep = "_")
  d1d2$lyr_soc_kgm2 = sum(df$lyr_soc_kgm2[1], df$lyr_soc_kgm2[2])
  d1d2$lyr_bot = df$lyr_bot[2]
  d1d2$fm <- sum(df$fm[1] * wt1, df$fm[2] * wt2)
  d1d2$d14c <- sum(df$d14c[1] * wt1, df$d14c[2] * wt2)
  return(rbind(d1d2,
               df[3:nrow(df), ]))
}
# 3) calc. wtd. average for GRrf
sra.2001.ls2$GRrf <- bind_rows(
  lapply(split(sra.2001.ls2$GRrf, sra.2001.ls2$GRrf$pro_rep), function(x) {
    d1d2.14c.fx(x)
  })
)
# 4) calc. wtd. average for BSrf
#    - problem here is that only one pro_rep has 0-3 cm data
#    - so, need to calculate weighted SOC, then calculate weighted 14C
#    - composite 0-8 = 15g BSrf_1_0-3 + 5 g from each pro_rep BSrf_3-8
BSrf_comp_01_i <- sra.2001.ls2$BSrf[which(sra.2001.ls$BSrf$lyr_bot < 9), ]
BSrf_comp_01_i$soc_wt <- c(15 / 30, rep(5 / 30, 3))
BSrf_comp_01_i$soc_wtd <- BSrf_comp_01_i$lyr_soc_kgm2 * BSrf_comp_01_i$soc_wt

# create summarized list
sra.2001.sum.ls2  <- lapply(sra.2001.ls2, function(df) {
  data.frame(
    df %>%
      filter(lyr_bot <= 40) %>%
      mutate(lyr_bot_ch = as.character(lyr_bot)) %>%
      select(PMeco, d14c, fm, lyr_bot_ch, lyr_soc_kgm2) %>%
      group_by(PMeco, lyr_bot_ch) %>%
      summarize(
        across(where(is.numeric), list(mean = mean, sd = sd), na.rm = TRUE)) %>%
      mutate(lyr_bot = as.numeric(lyr_bot_ch)) %>%
      select(-lyr_bot_ch)
  )
})

# remove BSrf row w/ lyr_bot = 3
sra.2001.sum.ls2$BSrf <- sra.2001.sum.ls2$BSrf[-which(sra.2001.sum.ls2$BSrf$lyr_bot == 3), ]
# calculate weighted average for d14c, fm, lyr_soc_kgm2
sra.2001.sum.ls2$BSrf[which(sra.2001.sum.ls2$BSrf$lyr_bot == 8), "d14c_mean"] <- sum(BSrf_comp_01_i$d14c * (BSrf_comp_01_i$soc_wtd / sum(BSrf_comp_01_i$soc_wtd)))
sra.2001.sum.ls2$BSrf[which(sra.2001.sum.ls2$BSrf$lyr_bot == 8), "fm_mean"] <- sum(BSrf_comp_01_i$fm * (BSrf_comp_01_i$soc_wtd / sum(BSrf_comp_01_i$soc_wtd)))
sra.2001.sum.ls2$BSrf[which(sra.2001.sum.ls2$BSrf$lyr_bot == 8), "lyr_soc_kgm2_mean"] <- sum(BSrf_comp_01_i$soc_wtd)
sra.2001.sum.ls2$BSrf[which(sra.2001.sum.ls2$BSrf$lyr_bot == 8), c("d14c_sd", "fm_sd", "lyr_soc_kgm2_sd")] <- NA

# calculate cmtv soc
sra.2001.sum.ls2 <- lapply(sra.2001.sum.ls2, function(x) {
  x <- x[order(x$lyr_bot), ]
  x$lyr_soc_cmtv <- NA
  for(i in seq_along(x$lyr_bot)) {
      if(i == 1) {
        x$lyr_soc_cmtv[i] <- x$lyr_soc_kgm2_mean[i]
      } else {
        x$lyr_soc_cmtv[i] <- x$lyr_soc_kgm2_mean[i] + x$lyr_soc_cmtv[i-1] 
      }
  }
  return(x)
})

# make df
sra.01.sum <- data.frame(bind_rows(
  lapply(sra.2001.sum.ls2, function(df) {
    df %>%
      mutate(eco = factor(ifelse(grepl("pp", df$PMeco), "warm",
                                 ifelse(grepl("wf", df$PMeco), "cool", "cold")),
                          levels = c("warm", "cool", "cold")),
             pm = ifelse(grepl("AN", df$PMeco), "andesite",
                         ifelse(grepl("BS", df$PMeco), "basalt", "granite")),
             d14c_u = d14c_mean + d14c_sd,
             d14c_l = d14c_mean - d14c_sd,
             Year = 2001,
             Type = "bulk") %>%
      select(names(sra.01.inc)) %>%
      arrange(lyr_bot)
  })
))
# bind with inc
sra.01.inc.blk <- rbind(data.frame(sra.01.inc), sra.01.sum)
save(sra.01.inc.blk, file = "sra.01.inc.blk.RData")
ts <- bind_rows(sra.19a.co2.ts[ , nms], 
                sra.19b.co2.ts[ , nms], 
                sra.01.1.co2.ts[ , nms],
                sra.01.2.co2.ts[ , nms])
if(length(which(is.na(ts$mgCO2_jar))) > 0) {
  ts <- ts[-which(is.na(ts$mgCO2_jar)), ]
}
ts$year <- sapply(strsplit(as.character(ts$ID), "_"), "[[", 3)
ts$rep <- sapply(strsplit(as.character(ts$ID), "_"), "[[", 4)
ts$depth <- sapply(strsplit(as.character(ts$ID), "_"), "[[", 2)
ts$ID2 <- paste(ts$PMeco, ts$depth, sep = "_")

# add C content
ts[which(ts$year == 2001), "gC_gS"] <- soc.2001.sum2[match(ts[which(ts$year == 2001), "ID2"], soc.2001.sum2$ID2), "c_pct_avg"] * 10^-2
Error in soc.2001.sum2[match(ts[which(ts$year == 2001), "ID2"], soc.2001.sum2$ID2),  : 
  non-numeric argument to binary operator
fig.n <- 1
# function for plotting
ts.plot.fx <- function(df, yr, increment, cumulative = TRUE) {
      if (cumulative) {
        df %>%
          filter(year == yr & depth_index == increment) %>%
          mutate(PM = ifelse(grepl("AN", PMeco), "AN",
                             ifelse(grepl("BS", PMeco), "BS", "GR")),
                 eco = factor(ifelse(grepl("rf", PMeco), "rf", 
                                     ifelse(grepl("wf", PMeco), "wf", "pp")),
                              levels = c("pp", "wf", "rf"))) %>%
          ggplot(., aes(time_d, mgCO2_gC_avg, color = PM, shape = eco)) +
          geom_ribbon(aes(ymin = mgCO2_gC_max, ymax = mgCO2_gC_min, fill = PM, linetype = eco, alpha = 0.2), show.legend = FALSE) +
          geom_point(aes(time_d, mgCO2_gC_max, fill = PM, shape = eco), color = "black", size = 3, stroke = 1) +
          geom_point(aes(time_d, mgCO2_gC_min, fill = PM, shape = eco), color = "black", size = 3, stroke = 1) +
          geom_line(aes(color = PM, linetype = eco), size = 1.2) +
          facet_grid(rows = vars(eco),
                     labeller = labeller(eco = c("rf" = "cold", "wf" = "cool", "pp" = "warm"))) +
          scale_x_continuous(limits = c(0,30)) +
          scale_color_manual(name = "Parent material",
                             labels = c("AN" = "andesite",
                                        "BS" = "basalt",
                                        "GR" = "granite"),
                             values = c("AN" = "blue", 
                                        "BS" = "red", 
                                        "GR" = "darkgray")) +
          scale_shape_manual(name = "Climate",
                             labels = c("rf" = "cold",
                                        "wf" = "cool",
                                        "pp" = "warm"),
                             values = c("pp" = 21, 
                                        "rf" = 22, 
                                        "wf" = 24)) +
          scale_fill_manual(values =c("AN" = "blue",
                                      "BS" = "red",
                                      "GR" = "darkgray")) +
          scale_linetype_manual(name = "Climate",
                                values = c("rf" = "dotted",
                                           "wf" = "dashed",
                                           "pp" = "solid"),
                                labels = c("rf" = "cold",
                                        "wf" = "cool",
                                        "pp" = "warm")) +
          ylab(expression('Cumulative flux (mgCO'[2]*'-C gC'^-1*')')) +
          xlab("Time (days)") +
          guides(color = guide_legend(order = 1),
                 shape = guide_legend(order = 3)) +
          ggtitle(paste("Cumulative flux, ", yr, "depth ", increment)) +
          theme_bw() +
          theme(panel.grid = element_blank())
    } else {
       df %>%
        filter(year == yr & depth_index == increment) %>%
        mutate(PM = ifelse(grepl("AN", PMeco), "AN",
                           ifelse(grepl("BS", PMeco), "BS", "GR")),
              eco = factor(ifelse(grepl("rf", PMeco), "rf",
                                  ifelse(grepl("wf", PMeco), "wf", "pp")),
                           levels = c("pp", "wf", "rf"))) %>%
        ggplot(., aes(time_d, mgCO2_gC_d_avg, color = PM, shape = eco)) +
        geom_ribbon(aes(ymin = mgCO2_gC_d_max, ymax = mgCO2_gC_d_min, fill = PM, linetype = eco, alpha = 0.2), show.legend = FALSE) +
          geom_point(aes(time_d, mgCO2_gC_d_max, fill = PM, shape = eco), color = "black", size = 3, stroke = 1) +
          geom_point(aes(time_d, mgCO2_gC_d_min, fill = PM, shape = eco), color = "black", size = 3, stroke = 1) +
        geom_line(aes(color = PM, linetype = eco), size = 1.2) +
        facet_grid(rows = vars(eco),
                   labeller = labeller(eco = c("rf" = "cold", "wf" = "cool", "pp" = "warm"))) +
        scale_x_continuous(limits = c(0,30)) +
        scale_color_manual(name = "Parent material",
                           labels = c("AN" = "andesite",
                                      "BS" = "basalt",
                                      "GR" = "granite"),
                           values = c("AN" = "blue", 
                                      "BS" = "red", 
                                      "GR" = "darkgray")) +
        scale_shape_manual(name = "Climate",
                           labels = c("rf" = "cold",
                                      "wf" = "cool",
                                      "pp" = "warm"),
                           values = c("pp" = 21, 
                                      "rf" = 22, 
                                      "wf" = 24)) +
        scale_fill_manual(values =c("AN" = "blue",
                                    "BS" = "red",
                                    "GR" = "darkgray")) +
        scale_linetype_manual(name = "Climate",
                              values = c("rf" = "dotted",
                                         "wf" = "dashed",
                                         "pp" = "solid"),
                              labels = c("rf" = "cold",
                                      "wf" = "cool",
                                      "pp" = "warm")) +
        ylab(expression('Respiration Rate (mgCO'[2]*'-C gC'^-1*'d'^-1*')')) +
        xlab("Time (days)") +
        guides(color = guide_legend(order = 1),
               shape = guide_legend(order = 3)) +
        ggtitle(paste("Flux rate", yr, "depth ", increment)) +
        theme_bw() +
        theme(panel.grid = element_blank())
    }
}

## cumulative flux
# 2019
ts.plot.fx(ts.avg, yr = "2019", increment = "1")
ts.plot.fx(ts.avg, yr = "2019", increment = "2")
ts.plot.fx(ts.avg, yr = "2019", increment = "3")
# 2001
ts.plot.fx(ts.avg, yr = "2001", increment = "1")
ts.plot.fx(ts.avg, yr = "2001", increment = "2")
ts.plot.fx(ts.avg, yr = "2001", increment = "3")

## flux rates
# 2019
ts.plot.fx(ts.avg, yr = "2019", increment = "1", cumulative = FALSE)
ts.plot.fx(ts.avg, yr = "2019", increment = "2", cumulative = FALSE)
ts.plot.fx(ts.avg, yr = "2019", increment = "3", cumulative = FALSE)
# 2001
ts.plot.fx(ts.avg, yr = "2001", increment = "1", cumulative = FALSE)
ts.plot.fx(ts.avg, yr = "2001", increment = "2", cumulative = FALSE)
ts.plot.fx(ts.avg, yr = "2001", increment = "3", cumulative = FALSE)

Fig. 16. Respiration data from incubations of 2019 and 2001 bulk soils.

Caption: Points show measured CO2 production of laboratory duplicates as cumulative fluxes or daily flux rates by depth, lines show the means, and the ribbon represents the range.

# plot 2019
fig.n <- fig.n + 1
# p <-
sra.19.inc.blk %>%
  mutate(ECOtype = paste0(eco, " (", Type, ")")) %>%
  arrange(lyr_bot) %>%
  ggplot(., aes(d14c_mean, lyr_bot, color = pm, shape = ECOtype, linetype = Type)) +
  geom_vline(xintercept = atm.d14.2019) +
  geom_hline(yintercept = 0) +
  geom_point(size = 3) +
  geom_errorbarh(
    aes(xmin = d14c_l, 
        xmax = d14c_u,
        color = pm), 
    height = 1.5) +
  geom_path() +
  scale_y_reverse() +
  scale_color_manual(name = "Parent material",
                     values = c("andesite" = "blue", 
                                "basalt" = "red", 
                                "granite" = "darkgray")) +
  scale_shape_manual(name = "Ecosystem (type)",
                     values = c("warm (bulk)" = 15, 
                                "cool (bulk)" = 16, 
                                "cold (bulk)" = 17,
                                "warm (inc)" = 0, 
                                "cool (inc)" = 1, 
                                "cold (inc)" = 2)) +
  xlab(expression(Delta*''^14*'C (‰)')) +
  ylab("Depth (cm)") +
  facet_grid(rows = vars(eco), cols = vars(pm)) +
  theme_bw() +
  theme(panel.grid.minor = element_blank())

# ggsave("sra.bulkInc.19.pdf", p, device = cairo_pdf, width = 9.5, height = 5, units = "in")

Fig. 16. \(\Delta\)14C of 2019 bulk soil incubations and corresponding bulk soil

Caption: \(\Delta\)14C of bulk soil and respired CO2 by depth for each site in 2019. Error bars show one standard deviation for bulk soil, points show mean of three replicate profiles for bulk soils and single observations for respired CO2.

# plot 2001
fig.n <- fig.n + 1
sra.01.inc.blk %>%
  mutate(ECOtype = paste0(eco, " (", Type, ")")) %>%
  ggplot(., aes(d14c_mean, lyr_bot, color = pm, shape = ECOtype, linetype = Type)) +
  geom_vline(xintercept = atm.d14.2001) +
  geom_hline(yintercept = 0) +
  geom_point(size = 3) +
  geom_errorbarh(
    aes(xmin = d14c_l, 
        xmax = d14c_u,
        color = pm), 
    height = 1.5) +
  geom_path() +
  scale_y_reverse() +
  scale_color_manual(name = "Parent material",
                     values = c("andesite" = "blue", 
                                "basalt" = "red", 
                                "granite" = "darkgray")) +
  scale_shape_manual(name = "Ecosystem (type)",
                     values = c("warm (bulk)" = 15, 
                                "cool (bulk)" = 16, 
                                "cold (bulk)" = 17,
                                "warm (inc)" = 0, 
                                "cool (inc)" = 1, 
                                "cold (inc)" = 2)) +
  scale_x_continuous(limits = c(-100, 200)) +
  xlab(expression(Delta*''^14*'C (‰)')) +
  ylab("Depth (cm)") +
  facet_grid(rows = vars(eco), cols = vars(pm)) +
  theme_bw() +
  theme(panel.grid.minor = element_blank())

Fig. 16. \(\Delta\)14C of 2001 bulk soil incubations and corresponding bulk soil

Caption: \(\Delta\)14C of bulk soil and respired CO2 by depth for each site in 2001. Points show mean of three replicate profiles for bulk soils and mean of laboratory duplicates for respired CO2. The incubated soil samples are a composite made by homogenizing subsamples from each of the three replicate profile samples by depth. Error bars show one standard deviation for bulk soil and the measured values from laboratory duplicates of the incubated composite samples.

# first merge mean 14C data from 2019 samples with composite incubation data
nms.inc.blk <- c("pm", "eco", "lyr_bot", "Year")
sra.19.inc.blk2 <- left_join(sra.19.bulk %>% mutate(., Year = as.factor(Year)),
                             sra.2019.inc.sum.df,
                             by = nms.inc.blk,
                             suffix = c(".bulk", ".inc"))
# 2001
sra.01.inc.blk2 <- left_join(sra.01.sum %>% mutate(., Year = as.factor(Year)),
                             sra.01.inc,
                             by = nms.inc.blk,
                             suffix = c(".bulk", ".inc"))
sra.01.inc.blk2$PMeco <- paste0(sra.01.inc.blk2$pm, sra.01.inc.blk2$eco)
# add depth factor
sra.01.inc.blk2 <- unsplit(
  lapply(split(sra.01.inc.blk2, sra.01.inc.blk2$PMeco), function(x) {
  x$depth <- seq(1, nrow(x))
  return(x) 
  }), 
sra.01.inc.blk2$PMeco)
sra.01.inc.blk2 <- sra.01.inc.blk2[which(sra.01.inc.blk2$lyr_bot < 35), ]
sra.01.inc.blk2$depth <- factor(sra.01.inc.blk2$depth)

# regress bulk vs. inc
min.inc.blk.19 <- min(sra.19.inc.blk2$d14c_l.inc,
                      sra.19.inc.blk2$d14c_l.bulk) # exclude highly negative incubation sample from GRwf
max.inc.blk.19 <- max(sra.19.inc.blk2$d14c_l.inc,
                      sra.19.inc.blk2$d14c_l.bulk)

# What is the ideal grouping/expected relationship?
## look at combinatorial dataset
# sra.all.df.fx <- function(ls, year) {
#   cbind(bind_rows(lapply(ls, function(df) df[ , c("PMeco", "lyr_bot", "d14c")])),
#         year = year)
# }
# sra.all.df <- inner_join(
#   rbind(sra.all.df.fx(sra.2001.ls, 2001),
#         sra.all.df.fx(sra.2019.ls, 2019)),
#   rbind(sra.all.df.fx(sra.2001.inc.ls, 2001),
#         sra.all.df.fx(sra.2019.inc.ls, 2019)),
#   by = c("PMeco", "lyr_bot", "year"),
#   suffix = c("_bulk", "_inc"))
# sra.all.df <- sra.all.df %>%
#   mutate(PM = substr(PMeco, 1, 2),
#          ECO = substr(PMeco, 3, 4))
# 
# sra.all.df %>%
#   filter(d14c_inc > -130) %>%
#   ggplot(., aes(d14c_bulk, d14c_inc, color = PM)) +
#   geom_vline(xintercept = 0) +
#   geom_hline(yintercept = 0) +
#   geom_abline(slope = 1, intercept = 0) +
#   geom_smooth(method = "lm", formula = y ~ x, aes(fill = PM)) +
#   geom_point() +
#   scale_color_manual(name = "Parent material",
#                      values = c("AN" = "blue",
#                                 "BS" = "red",
#                                 "GR" = "darkgray"),
#                      labels = c("AN" = "andesite",
#                                 "BS" = "basalt",
#                                 "GR" = "granite")) +
#     scale_fill_manual(name = "Parent material",
#                      values = c("AN" = "blue",
#                                 "BS" = "red",
#                                 "GR" = "darkgray"),
#                      labels = c("AN" = "andesite",
#                                 "BS" = "basalt",
#                                 "GR" = "granite")) +
#   coord_fixed(xlim = c(-130, 200), ylim = c(-130, 200)) +
#   xlab(expression('Bulk soil '*Delta*''^14*'C (‰)')) +
#   ylab(expression('Incubation '*Delta*''^14*'C (‰)')) +
#   theme_bw() +
#   theme(panel.grid.minor = element_blank())
#   
# summary(lm(d14c_inc ~ d14c_bulk * PM, sra.all.df[sra.all.df$d14c_inc > -130, ]))

# join all data as means and sds
sra.all.sum.df <- left_join(
  bind_rows(sra.2001.sum.ls2) %>%
    select(PMeco, lyr_bot, d14c_mean, d14c_sd) %>%
    mutate(Year = 2001) %>%
    bind_rows(., 
              bind_rows(lapply(sra.2019.ls, function(df) {
                df %>%
                  filter(lyr_bot < 31) %>%
                  select(PMeco, lyr_bot, d14c) %>%
                  group_by(PMeco, lyr_bot) %>%
                  summarize(across(d14c, list(mean = mean, sd = sd))) %>%
                  mutate(Year = 2019)
                }))
            ),
  bind_rows(lapply(sra.2001.inc.ls, function(df) {
              df %>%
                select(PMeco, lyr_bot, d14c) %>%
                group_by(PMeco, lyr_bot) %>%
                summarize(across(d14c, list(mean = mean, sd = sd))) %>%
                mutate(Year = 2001) 
              })) %>%
  bind_rows(., 
            bind_rows(lapply(sra.2019.inc.ls, function(df) {
              df %>%
                select(PMeco, lyr_bot, d14c) %>%
                group_by(PMeco, lyr_bot) %>%
                summarize(across(d14c, list(mean = mean, sd = sd))) %>%
                mutate(Year = 2019)
              }))
            ), 
  by = c("PMeco", "lyr_bot", "Year"),
  suffix = c(".bulk", ".inc")) %>%
  mutate(PM = substring(PMeco, 1, 2),
         eco = substring(PMeco, 3, 4))

# Trend for means
# NB Year only, depth only models do not show significant interactions
# PM only model
emtrends(lm(d14c_mean.inc ~ d14c_mean.bulk * PM, sra.all.sum.df[sra.all.sum.df$d14c_mean.inc > -200, ]), pairwise ~ PM, var = "d14c_mean.bulk")
$emtrends
 PM d14c_mean.bulk.trend    SE df lower.CL upper.CL
 AN                0.514 0.144 42    0.224    0.804
 BS                0.873 0.169 42    0.532    1.214
 GR                0.952 0.136 42    0.679    1.226

Confidence level used: 0.95 

$contrasts
 contrast estimate    SE df t.ratio p.value
 AN - BS   -0.3593 0.222 42 -1.621  0.2481 
 AN - GR   -0.4387 0.198 42 -2.221  0.0792 
 BS - GR   -0.0794 0.216 42 -0.367  0.9287 

P value adjustment: tukey method for comparing a family of 3 estimates 
# ECO only model
emtrends(lm(d14c_mean.inc ~ d14c_mean.bulk * eco, sra.all.sum.df[sra.all.sum.df$d14c_mean.inc > -200, ]), pairwise ~ eco, var = "d14c_mean.bulk")
$emtrends
 eco d14c_mean.bulk.trend    SE df lower.CL upper.CL
 pp                 0.779 0.145 42    0.487    1.071
 rf                 0.777 0.317 42    0.137    1.417
 wf                 0.606 0.147 42    0.308    0.903

Confidence level used: 0.95 

$contrasts
 contrast estimate    SE df t.ratio p.value
 pp - rf   0.00222 0.349 42 0.006   1.0000 
 pp - wf   0.17373 0.206 42 0.841   0.6797 
 rf - wf   0.17150 0.350 42 0.491   0.8762 

P value adjustment: tukey method for comparing a family of 3 estimates 
# lapply(split(sra.all.sum.df, sra.all.sum.df$eco), function(df) {
#   summary(lm(d14c_mean.inc ~ d14c_mean.bulk * PM, df))
# })

# # Deming regression (accounts for error in x and y terms)
# sra.dem <- lapply(split(sra.all.sum.df, sra.all.sum.df$PM), function(df) {
#   deming(d14c_mean.inc ~ d14c_mean.bulk,
#        data = df, xstd = d14c_sd.inc, ystd = d14c_sd.bulk)
# })

# all depths and years together, by PM
fig.n <- fig.n + 1
sra.19.inc.blk2  %>%
  bind_rows(., sra.01.inc.blk2[ , which(names(sra.19.inc.blk2) %in% names(sra.01.inc.blk2))]) %>%
  mutate(depth = factor(lyr_bot),
         ecoYear = paste0(eco, " (", Year, ")")) %>%
  filter(d14c_mean.inc > -200) %>%
  ggplot(., aes(d14c_mean.bulk, d14c_mean.inc, color = pm)) +
  # geom_vline(xintercept = atm.d14.2019, linetype = "dashed") +
  geom_vline(xintercept = 0) +
  # geom_hline(yintercept = atm.d14.2019, linetype = "dashed") +
  geom_hline(yintercept = 0) +
  geom_abline(slope = 1, intercept = 0) +
  geom_point(aes(color = pm, shape = ecoYear), size = 3) +
  geom_smooth(method = "lm", formula = y ~ x, se = FALSE) +
  geom_errorbarh(
    aes(xmin = d14c_l.bulk, 
        xmax = d14c_u.bulk,
        color = pm), 
    height = 1.5) +
  geom_errorbar(
    aes(ymin = d14c_l.inc, 
        ymax = d14c_u.inc,
        color = pm), 
    width = 1.5) +
  scale_color_manual(name = "Parent material",
                     values = c("andesite" = andesite,
                                "basalt" = basalt,
                                "granite" = granite)) +
  scale_shape_manual(name = "Ecosystem (year)",
                     values = c("warm (2019)" = 0,
                                "cool (2019)" = 2,
                                "cold (2019)" = 1,
                                "warm (2001)" = 15,
                                "cool (2001)" = 17,
                                "cold (2001)" = 16)) +
  coord_fixed(xlim = c(-100, 200), ylim = c(-100, 200)) +
  xlab(expression('Bulk soil '*Delta*''^14*'C (‰)')) +
  ylab(expression('Incubation '*Delta*''^14*'C (‰)')) +
  # facet_grid(rows = vars(depth)) +
  theme_bw() +
  theme(panel.grid = element_blank())


sra.19.inc.blk2  %>%
  bind_rows(., sra.01.inc.blk2[ , which(names(sra.19.inc.blk2) %in% names(sra.01.inc.blk2))]) %>%
  mutate(depth = factor(lyr_bot),
         ecoYear = paste0(eco, " (", Year, ")")) %>%
  filter(d14c_mean.inc > -200) %>%
  ggplot(., aes(d14c_mean.bulk, d14c_mean.inc, color = eco)) +
  # geom_vline(xintercept = atm.d14.2019, linetype = "dashed") +
  geom_vline(xintercept = 0) +
  # geom_hline(yintercept = atm.d14.2019, linetype = "dashed") +
  geom_hline(yintercept = 0) +
  geom_abline(slope = 1, intercept = 0) +
  geom_point(aes(color = eco, shape = ecoYear), size = 3) +
  geom_smooth(method = "lm", formula = y ~ x, se = FALSE) +
  geom_errorbarh(
    aes(xmin = d14c_l.bulk, 
        xmax = d14c_u.bulk,
        color = eco), 
    height = 1.5) +
  geom_errorbar(
    aes(ymin = d14c_l.inc, 
        ymax = d14c_u.inc,
        color = eco), 
    width = 1.5) +
  scale_color_manual(name = "Climate",
                     values = c("warm" = warm,
                                "cool" = cool,
                                "cold" = cold)) +
  scale_shape_manual(name = "Ecosystem (year)",
                     values = c("warm (2019)" = 0,
                                "cool (2019)" = 1,
                                "cold (2019)" = 2,
                                "warm (2001)" = 15,
                                "cool (2001)" = 16,
                                "cold (2001)" = 17)) +
  coord_fixed(xlim = c(-100, 200), ylim = c(-100, 200)) +
  xlab(expression('Bulk soil '*Delta*''^14*'C (‰)')) +
  ylab(expression('Incubation '*Delta*''^14*'C (‰)')) +
  # facet_grid(rows = vars(depth)) +
  theme_bw() +
  theme(panel.grid.minor = element_blank())


# # 2001
# sra.01.inc.blk2 %>%
#   filter(d14c_mean.bulk > -100 & d14c_mean.inc > -100) %>%
#   ggplot(., aes(d14c_mean.bulk, d14c_mean.inc, color = pm, shape = eco, group = pm)) +
#   # geom_vline(xintercept = atm.d14.2019, linetype = "dashed") +
#   geom_vline(xintercept = 0) +
#   # geom_hline(yintercept = atm.d14.2019, linetype = "dashed") +
#   geom_hline(yintercept = 0) +
#   geom_abline(slope = 1, intercept = 0) +
#   geom_point(size = 3) +
#   geom_smooth(method = "lm", formula = y ~ x, se = FALSE) +
#   geom_errorbarh(
#     aes(xmin = d14c_l.bulk, 
#         xmax = d14c_u.bulk,
#         color = pm), 
#     height = 1.5) +
#   geom_errorbar(
#     aes(ymin = d14c_l.inc, 
#         ymax = d14c_u.inc,
#         color = pm), 
#     width = 1.5) +
#   scale_color_manual(name = "Parent material",
#                      values = c("andesite" = "blue",
#                                 "basalt" = "red",
#                                 "granite" = "darkgray")) +
#   scale_shape_manual(name = "Ecosystem",
#                      values = c("warm" = 15,
#                                 "cool" = 16,
#                                 "cold" = 17)) +
#   coord_fixed(xlim = c(-100, 200), ylim = c(-100, 200)) +
#   xlab(expression('Bulk soil '*Delta*''^14*'C (‰)')) +
#   ylab(expression('Incubation '*Delta*''^14*'C (‰)')) +
#   facet_grid(rows = vars(depth)) +
#   theme_bw() +
#   theme(panel.grid.minor = element_blank())
# 
# # 2019
# fig.n <- fig.n + 1
# sra.19.inc.blk2 %>%
#   mutate(depth = factor(lyr_bot)) %>%
#   ggplot(., aes(d14c_mean.bulk, d14c_mean.inc, color = pm, shape = eco, group = pm)) +
#   # geom_vline(xintercept = atm.d14.2019, linetype = "dashed") +
#   geom_vline(xintercept = 0) +
#   # geom_hline(yintercept = atm.d14.2019, linetype = "dashed") +
#   geom_hline(yintercept = 0) +
#   geom_abline(slope = 1, intercept = 0) +
#   geom_point(size = 3) +
#   geom_smooth(method = "lm", formula = y ~ x, se = FALSE) +
#   geom_errorbarh(
#     aes(xmin = d14c_l.bulk, 
#         xmax = d14c_u.bulk,
#         color = pm), 
#     height = 1.5) +
#   geom_errorbar(
#     aes(ymin = d14c_l.inc, 
#         ymax = d14c_u.inc,
#         color = pm), 
#     width = 1.5) +
#   scale_color_manual(name = "Parent material",
#                      values = c("andesite" = "blue",
#                                 "basalt" = "red",
#                                 "granite" = "darkgray")) +
#   scale_shape_manual(name = "Ecosystem",
#                      values = c("warm" = 0,
#                                 "cool" = 1,
#                                 "cold" = 2)) +
#   coord_fixed(xlim = c(-100, 200), ylim = c(-100, 200)) +
#   xlab(expression('Bulk soil '*Delta*''^14*'C (‰)')) +
#   ylab(expression('Incubation '*Delta*''^14*'C (‰)')) +
#   facet_grid(rows = vars(depth)) +
#   theme_bw() +
#   theme(panel.grid.minor = element_blank())

Fig. 16. Regression of 2019 bulk soil incubations and corresponding bulk soil \(\Delta\)14C

Caption: Regressions of \(\Delta\)14C of bulk soil and respired CO2 by depth for each site in 2019. Error bars show one standard deviation for bulk soil, points show mean of three replicate profiles for bulk soils and single observations for respired CO2.

Time series: \(\Delta\)14C by depth (as measured)

# combine '01, '09, '19 data
sra.01.19.raw <- rbind(bind_rows(sra.2001.sum.ls),
                       bind_rows(sra.2019.sum.ls))
sra.2009.df <- sra.09.sum[ , which(names(sra.09.sum) %in% names(sra.01.19.raw))]
sra.2009.df <- cbind(sra.2009.df, 
                     fm = NA,
                     d14c_sd = NA,
                     fm_sd = NA,
                     d14c_u = NA,
                     d14c_l = NA)
sra.01.09.19.raw <- rbind(sra.01.19.raw, sra.2009.df)
sra.01.09.19.raw$Year <- factor(c(rep(2001, nrow(bind_rows(sra.2001.sum.ls))),
                                  rep(2019, nrow(bind_rows(sra.2019.sum.ls))),
                                  rep(2009, nrow(sra.2009.df))),
                                levels = c("2001", "2009", "2019"))

# plot
# w/ ribbons
# sra.01.09.19.raw %>%
#   mutate(PMeco_year = paste0(PMeco, Year),
#          eco = factor(ifelse(ECO == "pp", "warm",
#                       ifelse(ECO == "wf", "cool", "cold")),
#                       levels = c("warm", "cool", "cold")),
#          d14c_u = d14c + d14c_sd,
#          d14c_l = d14c - d14c_sd,
#          pm = ifelse(PM == "AN", "andesite",
#                      ifelse(PM == "BS", "basalt", "granite"))) %>%
#   ggplot(., aes(d14c, lyr_bot, group = PMeco_year)) +
#   geom_vline(xintercept = 0) +
#   geom_hline(yintercept = 0) +
#   geom_ribbon(aes(xmin = d14c_l, xmax = d14c_u, fill = pm, alpha = Year, group = PMeco_year),
#               color = NA, show.legend = FALSE) +
#   geom_point(aes(fill = pm, color = pm, shape = eco, alpha = Year), size = 2) +
#   geom_point(aes(shape = eco), color = "black", size = 3) +
#   geom_path(aes(linetype = Year, color = pm), size = 0.7) +
#   scale_y_reverse() +
#   scale_color_manual(name = "Parent material",
#                      values = c("andesite" = "blue", 
#                                 "basalt" = "red", 
#                                 "granite" = "darkgray")) +
#   scale_fill_manual(name = "Parent material",
#                     values = c("andesite" = "blue", 
#                                "basalt" = "red", 
#                                "granite" = "darkgray")) +
#   scale_shape_manual(name = "Ecosystem",
#                      values = c("warm" = 22, 
#                                 "cool" = 21, 
#                                 "cold" = 24)) +
#   scale_alpha_manual(values = c("2001" = .6,
#                                 "2009" = 0.4,
#                                 "2019" = 0.2)) +
#   facet_grid(rows = vars(eco), cols = vars(pm)) +
#   xlab(expression(Delta*''^14*'C (‰)')) +
#   ylab("Depth (cm)") +
#   theme_bw() +
#   theme(panel.grid.minor = element_blank())

# litter
sra.2019.inc.L.df <- data.frame(
  sra.2019.inc_L.df %>%
    group_by(Year, PM, eco, lyr_bot, PMeco) %>%
    summarize(across(.cols = d14c, 
                     .fns = list(mean = mean, min = min, max = max))) %>%
    rename(year = Year, d14c = d14c_mean) %>%
    mutate(eco = factor(ifelse(eco == "pp", "warm",
                      ifelse(eco == "wf", "cool", "cold")),
                      levels = c("warm", "cool", "cold")),
           pm = ifelse(PM == "AN", "andesite",
                       ifelse(PM == "BS", "basalt", "granite"))))
# for plotting below
sra.2019.inc.L.df2 <- sra.2019.inc.L.df %>%
  rename(d14c_l = d14c_min,
         d14c_u = d14c_max) %>%
  mutate(PMeco_year = paste0(PMeco, year))

# with error bars, all depths
sra.01.09.19.raw %>%
  mutate(PMeco_year = paste0(PMeco, Year),
         eco = factor(ifelse(ECO == "pp", "warm",
                      ifelse(ECO == "wf", "cool", "cold")),
                      levels = c("warm", "cool", "cold")),
         d14c_u = d14c + d14c_sd,
         d14c_l = d14c - d14c_sd,
         pm = ifelse(PM == "AN", "andesite",
                     ifelse(PM == "BS", "basalt", "granite"))) %>%
  ggplot(., aes(d14c, lyr_bot, group = PMeco_year)) +
  geom_vline(xintercept = 0) +
  geom_hline(yintercept = 0) +
  geom_point(aes(fill = pm, color = pm, shape = eco, alpha = Year), size = 3.5) +
  geom_point(data = sra.2019.inc.L.df2, 
             aes(d14c, lyr_bot, color = pm, shape = eco), shape = 8, size = 3.5, show.legend = FALSE) +
  geom_path(aes(linetype = Year, color = pm), size = 0.7) +
  geom_errorbarh(
    aes(xmin = d14c_l,
        xmax = d14c_u,
        color = pm,
        alpha = Year),
    height = 1.5) +
  scale_y_reverse() +
  scale_color_manual(name = "Parent material",
                     values = c("andesite" = "blue",
                                "basalt" = "red",
                                "granite" = "darkgray")) +
  scale_fill_manual(name = "Parent material",
                    values = c("andesite" = "blue",
                               "basalt" = "red",
                               "granite" = "darkgray")) +
  scale_shape_manual(name = "Ecosystem",
                     values = c("warm" = 15,
                                "cool" = 16,
                                "cold" = 17)) +
  scale_alpha_manual(values = c("2001" = 1,
                                "2009" = 0.6,
                                "2019" = 0.3)) +
  scale_linetype_manual(values = c("2001" = 1,
                                   "2009" = 2,
                                   "2019" = 3)) +
  facet_grid(rows = vars(eco), cols = vars(pm)) +
  xlab(expression(Delta*''^14*'C (‰)')) +
  ylab("Depth (cm)") +
  theme_bw() +
  theme(panel.grid.minor = element_blank())


# just topsoil, w/ error bars
fig.n <- fig.n + 1
sra.01.09.19.raw <- sra.01.09.19.raw[order(sra.01.09.19.raw$lyr_top), ]
sra.01.09.19.raw %>%
  mutate(PMeco_year = paste0(PMeco, Year),
         eco = factor(ifelse(ECO == "pp", "warm",
                      ifelse(ECO == "wf", "cool", "cold")),
                      levels = c("warm", "cool", "cold")),
         d14c_u = d14c + d14c_sd,
         d14c_l = d14c - d14c_sd,
         pm = ifelse(PM == "AN", "andesite",
                     ifelse(PM == "BS", "basalt", "granite"))) %>%
  ggplot(., aes(d14c, lyr_bot, group = PMeco_year)) +
  geom_vline(xintercept = 0) +
  geom_hline(yintercept = 0) +
  geom_point(aes(fill = pm, color = pm, shape = eco, alpha = Year), size = 3) +
  geom_path(aes(linetype = Year, color = pm), size = 0.7) +
  geom_errorbarh(
    aes(xmin = d14c_l,
        xmax = d14c_u,
        color = pm,
        alpha = Year),
    height = 1.5) +
  scale_y_reverse(limits = c(41, 0)) +
  scale_x_continuous(limits = c(-160, 190)) +
  scale_color_manual(name = "Parent material",
                     values = c("andesite" = "blue", 
                                "basalt" = "red", 
                                "granite" = "darkgray")) +
  scale_fill_manual(name = "Parent material",
                    values = c("andesite" = "blue", 
                               "basalt" = "red", 
                               "granite" = "darkgray")) +
  scale_shape_manual(name = "Ecosystem",
                     values = c("warm" = 15, 
                                "cool" = 16, 
                                "cold" = 17)) +
  scale_alpha_manual(values = c("2001" = 1,
                                "2009" = 0.6,
                                "2019" = 0.3)) +
  scale_linetype_manual(values = c("2001" = "solid",
                                   "2009" = "dashed",
                                   "2019" = "dotted")) +
  facet_grid(rows = vars(eco), cols = vars(pm)) +
  xlab(expression(Delta*''^14*'C (‰)')) +
  ylab("Depth (cm)") +
  theme_bw() +
  theme(panel.grid.minor = element_blank())

Fig. 16. Time series of \(\Delta\)14C by depth, as measured

Caption: Points show mean of three profile replicates for 2001, 2009, and 2019 samples. Error bars show ± 1 standard deviation of the mean (only a single profile was analyzed in 2009). Stars show litter incubation \(\Delta\)14C-CO2 for 2019 samples as a point of reference.

Spline fitting

Soils collected in both the 2001 and 2009 sampling campaigns were sampled by horizon, but the depth intervals differed between the two sampling years. In 2009, full profiles were excavated for each site, as opposed to the shorter profiles collected in 2001 from the GR and AN sites. Radiocarbon was measured on all three replicate profiles at each site for the 2001 samples, but only for one of the replicate profiles at each site in 2009, e.g. ANpp rep2, etc.

In order to compare the radiocarbon profiles between 2001, 2009, and 2019 we first interpolated both radiocarbon and carbon stock data at 1 cm intervals for each site in the datasets from each year. The carbon-stock-weighted radiocarbon values for any given target depth interval can then be calculated as a simple sum of the product of the carbon weight of each 1 cm increment (relative to the total carbon stock of the target depth interval) and its radiocarbon value. A monotonic cubic spline fit with Hyman filtering was used for the carbon stock interpolation (Wendt and Hauser 2013), and a mass-preserving spline was used to fit the radiocarbon data (Bishop, T.F.A., McBratney, A.B., Laslett, G.M., (1999) Modelling soil attribute depth functions with equal-area quadratic smoothing splines. Geoderma, 91(1-2): 27-45).

# 2001
sra.2001.soc.df <- bind_rows(lapply(seq_along(sra.2001.oc.sp.avg), function(i) {
  NM <- names(sra.2001.oc.sp.avg)[i]
  PM <- substr(NM, 1, 2)
  ECO <- substr(NM, 3, 4)
  df <- data.frame(PM = PM, ECO = ECO, lyr_soc_30 = sum(sra.2001.oc.sp.avg[[i]][1:30, "lyr_soc"]))
  df$ECO <- factor(df$ECO, levels = c("pp", "wf", "rf"))
  return(df)
}))

# 2009
sra.2009.soc.df <- bind_rows(lapply(seq_along(sra.2009.oc.sp), function(i) {
  NM <- names(sra.2009.oc.sp)[i]
  PM <- substr(NM, 1, 2)
  ECO <- substr(NM, 3, 4)
  df <- data.frame(PM = PM, ECO = ECO, lyr_soc_30 = sum(sra.2009.oc.sp[[i]][1:30, "lyr_soc"]))
  df$ECO <- factor(df$ECO, levels = c("pp", "wf", "rf"))
  return(df)
}))

# 2019
sra.2019.soc.df <- bind_rows(lapply(seq_along(sra.2019.oc.sp.avg), function(i) {
  NM <- names(sra.2019.oc.sp.avg)[i]
  PM <- substr(NM, 1, 2)
  ECO <- substr(NM, 3, 4)
  df <- data.frame(PM = PM, ECO = ECO, lyr_soc_30 = sum(sra.2019.oc.sp.avg[[i]][1:30, "lyr_soc"]))
  df$ECO <- factor(df$ECO, levels = c("pp", "wf", "rf"))
  return(df)
}))

ggplot(sra.2019.soc.df, aes(PM, lyr_soc_30, fill = PM)) +
  geom_col(position = "dodge") +
  scale_fill_manual(values = c("AN" = andesite, 
                               "BS" = basalt,
                               "GR" = granite)) +
  facet_grid(cols = vars(ECO)) +
  theme_bw() +
  theme(panel.grid = element_blank())


ggplot(sra.2009.soc.df, aes(PM, lyr_soc_30, fill = PM)) +
  geom_col(position = "dodge") +
  scale_fill_manual(values = c("AN" = andesite, 
                               "BS" = basalt,
                               "GR" = granite)) +
  facet_grid(cols = vars(ECO)) +
  theme_bw() +
  theme(panel.grid = element_blank())


ggplot(sra.2001.soc.df, aes(PM, lyr_soc_30, fill = PM)) +
  geom_col(position = "dodge") +
  scale_fill_manual(values = c("AN" = andesite, 
                               "BS" = basalt,
                               "GR" = granite)) +
  facet_grid(cols = vars(ECO)) +
  theme_bw() +
  theme(panel.grid = element_blank())


# all together
sra.01.09.19.soc.df <- cbind(rbind(sra.2001.soc.df,
                                   sra.2009.soc.df,
                                   sra.2019.soc.df), 
                             year = rep(c(2001, 2009, 2019), each = 9))
sra.01.09.19.soc.df %>%
  mutate(PMyear = paste0(PM, year)) %>%
  ggplot(., aes(PMyear, lyr_soc_30, fill = PM, alpha = year)) +
  geom_col(position = "dodge") +
  scale_fill_manual(values = c("AN" = andesite, 
                               "BS" = basalt,
                               "GR" = granite)) +
  facet_grid(cols = vars(ECO)) +
  theme_bw() +
  theme(panel.grid = element_blank())

#### 0-30cm
### bulk
## 2019
# SOC weights
cwt.19_30 <- lapply(seq_along(sra.2019.oc.sp), function(i) {
  lapply(sra.2019.oc.sp[[i]], function(df) {
    d <- 30
    c <- df[1:d, "lyr_soc"]
    return(unlist(lapply(c, function(x) x/sum(c))))
  })
})
names(cwt.19_30) <- names(sra.2019.oc.sp)
# FM wts
fm.wt.19_30 <- lapply(seq_along(cwt.19_30), function(i) {
  lapply(seq_along(cwt.19_30[[i]]), function(j) {
    df <- data.frame(cwt = cwt.19_30[[i]][[j]])
    df$fm <- sra.2019.fm.sp[[i]][[j]][["var.1cm"]][1:length(cwt.19_30[[i]][[j]])]
    df$fm_wt <- df$fm * df$cwt
  return(df)
  })
}) 
names(fm.wt.19_30) <- names(cwt.19_30)
# summarize over 0-30cm
sra.19.rep.30.ls <- lapply(seq_along(1:9), function(i) {
  lapply(seq_along(fm.wt.19_30[[i]]), function(x) {
    d <- 30
    f <- sum(fm.wt.19_30[[i]][[x]][1:d, "fm_wt"])
    return(unlist(f)) 
  })
})
sra.19.avg.30.ls <- lapply(seq_along(sra.2019.sum.ls), function(i) {
  fm <- lapply(seq_along(sra.19.rep.30.ls[[i]][[1]]), function(z) {
    data.frame(fm_19_mean = mean(sapply(sra.19.rep.30.ls[[i]], "[", z), na.rm = TRUE),
               fm_19_sd = sd(sapply(sra.19.rep.30.ls[[i]], "[", z), na.rm = TRUE))
    })
  return(bind_rows(fm))
})
names(sra.19.avg.30.ls) <- names(fm.wt.19_30)

## 2001
# SOC weights
cwt.01_30 <- lapply(sra.2001.oc.sp, function(ls) {
  lapply(ls, function(df) {
    d <- 30
    c <- df[1:d, "lyr_soc"]
    return(unlist(lapply(c, function(x) x/sum(c))))
  })
})
names(cwt.01_30) <- names(sra.2001.oc.sp)
# FM wts
fm.wt.01_30 <- lapply(seq_along(cwt.01_30), function(i) {
  lapply(seq_along(cwt.01_30[[i]]), function(j) {
    df <- data.frame(cwt = cwt.01_30[[i]][[j]])
    df$fm <- sra.2001.fm.sp[[i]][[j]][["var.1cm"]][1:length(cwt.01_30[[i]][[j]])]
    # linear extrapolation for filling 20-30cm fm data
    fm_1_30 <- df$fm[1:30] # 0-30cm fm
    if(length(which(is.na(fm_1_30))) > 0) {
     ix <- which(is.na(fm_1_30))
     ix.min <- min(ix) # first is.na(fm)
     m <- fm_1_30[ix.min-1]-fm_1_30[ix.min-2] # slope at last two measurement points
     for(i in ix.min:30) {
      fm_1_30[i] <- fm_1_30[i - 1] + m 
     }
     df$fm[1:30] <- fm_1_30 
    }
    df$fm_wt <- df$fm * df$cwt
  return(df)
  })
}) 
names(fm.wt.01_30) <- names(cwt.01_30)
# summarize over 0-30cm
sra.01.rep.30.ls <- lapply(seq_along(1:9), function(i) {
  lapply(seq_along(fm.wt.01_30[[i]]), function(x) {
    d <- 30
    f <- sum(fm.wt.01_30[[i]][[x]][1:d, "fm_wt"])
    return(unlist(f)) 
  })
})
sra.01.avg.30.ls <- lapply(seq_along(1:9), function(i) {
  fm <- lapply(seq_along(sra.01.rep.30.ls[[i]][[1]]), function(z) {
    data.frame(fm_01_mean = mean(sapply(sra.01.rep.30.ls[[i]], "[", z), na.rm = TRUE),
               fm_01_sd = sd(sapply(sra.01.rep.30.ls[[i]], "[", z), na.rm = TRUE))
    })
  return(bind_rows(fm))
})
names(sra.01.avg.30.ls) <- names(fm.wt.01_30)

### inc
## 2019
# SOC weights (site average)
cwt.19_30.avg <- lapply(cwt.19_30, function(ls) {
  apply(bind_rows(ls), 1, mean)
})
# FM weights
fm.wt.19.30.inc <- lapply(seq_along(cwt.19_30.avg), function(j) {
  lapply(sra.2019.inc.fm.sp[[j]], function(fm) {
    df <- data.frame(cwt = cwt.19_30.avg[[j]])
    df$fm <- fm
    df$fm_wt <- df$fm * df$cwt
  return(df)
  })
}) 
names(fm.wt.19.30.inc) <- names(cwt.19_30.avg)
# summarize over 0-30cm
sra.19.30.inc.ls <- lapply(fm.wt.19.30.inc, function(ls) {
  ls <- lapply(ls, function(df) sum(df$fm_wt))
  names(ls) <- c("fm_19_mean", "fm_19_min", "fm_19_max")
  return(data.frame(bind_rows(ls)))
})
names(sra.19.30.inc.ls) <- names(cwt.19_30.avg)

## 2001
# SOC weights (site average)
cwt.01_30.avg <- lapply(cwt.01_30, function(ls) {
  apply(bind_rows(ls), 1, mean)
})
# FM weights
fm.wt.01.30.inc <- lapply(seq_along(cwt.01_30.avg), function(j) {
  lapply(sra.2001.inc.fm.sp[[j]], function(fm) {
    df <- data.frame(cwt = cwt.01_30.avg[[j]])
    df$fm <- fm[1:length(cwt.01_30.avg[[j]])]
    # linear extrapolation for filling 20-30cm fm data
    fm_1_30 <- df$fm[1:30] # 0-30cm fm
    if(length(which(is.na(fm_1_30))) > 0) {
     ix <- which(is.na(fm_1_30))
     ix.min <- min(ix) # first is.na(fm)
     m <- fm_1_30[ix.min-1]-fm_1_30[ix.min-2] # slope at last two measurement points
     for(i in ix.min:30) {
      fm_1_30[i] <- fm_1_30[i - 1] + m 
     }
     df$fm[1:30] <- fm_1_30 
    }
    df$fm_wt <- df$fm * df$cwt
  return(df)
  })
}) 
names(fm.wt.01.30.inc) <- names(cwt.01_30.avg)
# summarize over 0-30cm
sra.01.30.inc.ls <- lapply(fm.wt.01.30.inc, function(ls) {
  ls <- lapply(ls, function(df) sum(df$fm_wt))
  names(ls) <- c("fm_01_mean", "fm_01_min", "fm_01_max")
  return(data.frame(bind_rows(ls)))
})
names(sra.01.30.inc.ls) <- names(cwt.01_30.avg)

## df for linear modeling
# bulk
sra.blk.rep.30.ls <- lapply(seq_along(sra.01.rep.30.ls), function(i) {
  blk.01 <- data.frame(fm_blk = do.call(rbind, sra.01.rep.30.ls[[i]]),
                       year = 2001)
  blk.19 <- data.frame(fm_blk = do.call(rbind, sra.19.rep.30.ls[[i]]),
                       year = 2019)
  rbind(blk.01, blk.19) %>%
    mutate(d14c_blk = calc_14c(fm_blk, year))
})
names(sra.blk.rep.30.ls) <- names(sra.01.30.inc.ls)
sra.blk.rep.30.df <- bind_rows(sra.blk.rep.30.ls, .id = "PMeco")
# inc
inc.30.bind.fx <- function(ls, year_xx) {
  rbind(
    bind_rows(lapply(ls, "[", 2), .id = "PMeco") %>%
      rename(fm_inc = paste0("fm_", year_xx, "_min")),
    bind_rows(lapply(ls, "[", 3), .id = "PMeco") %>%
      rename(fm_inc = paste0("fm_", year_xx, "_max"))) %>%
    mutate(year = as.numeric(paste0("20", year_xx))) %>%
    mutate(d14c_inc = calc_14c(fm_inc, year))
}
sra.inc.rep.30.df <- rbind(inc.30.bind.fx(sra.01.30.inc.ls, "01"), 
                           inc.30.bind.fx(sra.19.30.inc.ls, "19"))
# combine
sra.blk.inc.rep.30.df <- merge(sra.blk.rep.30.df, sra.inc.rep.30.df, by = c("year", "PMeco"))
save(sra.blk.inc.rep.30.df, file = "sra.blk.inc.rep.30.df.RData")

## Combine mean data into a single data frame
# functions for converting fm to d14c and calculating sd
blk.14c.sd.fx <- function(df, year_xx) {
  date <- as.numeric(paste0(20, year_xx))
  df$fm_u <- df[[paste0("fm_", year_xx, "_mean")]] + df[[paste0("fm_", year_xx, "_sd")]]
  df$d14c_u <- calc_14c(df$fm_u, date)
  df[[paste0("d14c_", "mean")]] <- calc_14c(df[[paste0("fm_", year_xx, "_mean")]], date)
  df[[paste0("d14c_", "sd")]] <- df[[paste0("d14c_", "mean")]] - df$d14c_u
  df$year <- as.numeric(paste0(20, year_xx))
  return(df %>% select(c(starts_with("d14c"), year)) %>% select(-d14c_u))
}
inc.14c.sd.fx <- function(df, year_xx) {
  names(df) <- gsub(paste0("fm_", year_xx), "d14c", names(df))
  df_14c <- calc_14c(df, as.numeric(paste0(20, year_xx)))
  df_14c[[paste0("d14c_", "sd")]] <- sd(df_14c[ , 2:3])
  df_14c$year <- as.numeric(paste0(20, year_xx))
  return(df_14c[ , c(1, 4:5)])
}
# run functions and combine lists 
# 0-30cm data from '01 and '19
sra.30.blk.inc.ls <- lapply(
  list(lapply(sra.01.30.inc.ls, inc.14c.sd.fx, year_xx = "01"), 
       lapply(sra.19.30.inc.ls, inc.14c.sd.fx, year_xx = "19"),
       lapply(sra.01.avg.30.ls, blk.14c.sd.fx, year_xx = "01"),
       lapply(sra.19.avg.30.ls, blk.14c.sd.fx, year_xx = "19")),
  bind_rows, .id = "PMeco")
# reduce list to data frame, calculate difference of means and sd
sra.30.blk.inc.df <- rbind(merge(sra.30.blk.inc.ls[[1]],
                                 sra.30.blk.inc.ls[[3]],
                                 by = c("PMeco", "year"), suffixes = c("_inc", "_blk")),
                           merge(sra.30.blk.inc.ls[[2]],
                                 sra.30.blk.inc.ls[[4]],
                                 by = c("PMeco", "year"), suffixes = c("_inc", "_blk"))) %>%
  mutate(blk.inc = d14c_mean_blk - d14c_mean_inc,
         blk.inc.sd = sqrt(d14c_sd_blk^2/3 + d14c_sd_inc^2/2))
fig.n <- fig.n + 1
sra.01.09.19 %>%
  mutate(PMeco_year = paste0(PMeco, Year),
         eco = factor(ifelse(ECO == "pp", "warm",
                      ifelse(ECO == "wf", "cool", "cold")),
                      levels = c("warm", "cool", "cold")),
         d14c_u = d14c + d14c_sd,
         d14c_l = d14c - d14c_sd,
         pm = ifelse(PM == "AN", "andesite",
                     ifelse(PM == "BS", "basalt", "granite"))) %>%
  # filter(Year != "2009") %>%
  ggplot(., aes(d14c, lyr_bot, color = pm, shape = eco, linetype = Year, group = PMeco_year)) +
  geom_vline(xintercept = 0) +
  geom_hline(yintercept = 0) +
  geom_point(aes(alpha = Year), size = 3) +
  geom_path(aes(linetype = Year)) +
  geom_errorbarh(
    aes(xmin = d14c_l, 
        xmax = d14c_u,
        color = pm), 
    height = 1.5) +
  scale_y_reverse() +
  scale_x_continuous() +    
  scale_color_manual(name = "Parent material",
                     values = c("andesite" = "blue", 
                                "basalt" = "red", 
                                "granite" = "darkgray")) +
  scale_shape_manual(name = "Ecosystem",
                     values = c("warm" = 15, 
                                "cool" = 16, 
                                "cold" = 17)) +
  scale_alpha_manual(values = c("2001" = 1,
                                "2009" = 0.6,
                                "2019" = 0.3)) +
  scale_linetype_manual(values = c("2001" = "solid",
                                 "2009" = "dashed",
                                 "2019" = "dotted")) +
  facet_grid(rows = vars(eco), cols = vars(pm)) +
  xlab(expression(Delta*''^14*'C (‰)')) +
  ylab("Depth (cm)") +
  theme_bw() +
  theme(panel.grid.minor = element_blank())

Fig. 16. Time series of bulk soil \(\Delta\)14C by 2001 depths (2001, 2009, 2019 samples)

Caption: Points for 2001 samples show the mean \(\Delta\)14C values at the measured depths. Points for 2009 and 2019 samples are spline-fitted estimates of \(\Delta\)14C predicted for the same depth intervals as measured in 2001. Error bars show ± 1 standard deviation of the mean of three replicate profiles for 2001 and 2019 samples (only a single profile was analyzed in 2009).

fig.n <- fig.n + 1
sra.19.01.09 %>%
  mutate(PMeco_year = paste0(PMeco, Year),
         eco = factor(ifelse(ECO == "pp", "warm",
                      ifelse(ECO == "wf", "cool", "cold")),
                      levels = c("warm", "cool", "cold")),
         d14c_u = d14c + d14c_sd,
         d14c_l = d14c - d14c_sd,
         pm = ifelse(PM == "AN", "andesite",
                     ifelse(PM == "BS", "basalt", "granite"))) %>%
  ggplot(., aes(d14c, lyr_bot, color = pm, shape = eco, linetype = Year, group = PMeco_year)) +
  geom_vline(xintercept = 0) +
  geom_hline(yintercept = 0) +
  geom_point(aes(alpha = Year), size = 3) +
  geom_path(aes(linetype = Year)) +
  geom_errorbarh(
    aes(xmin = d14c_l, 
        xmax = d14c_u,
        color = pm), 
    height = 1.5) +
  # scale_y_reverse(limits = c(30, 0)) +
  scale_y_reverse() +
  scale_x_continuous() +    
  scale_color_manual(name = "Parent material",
                     values = c("andesite" = "blue", 
                                "basalt" = "red", 
                                "granite" = "darkgray")) +
  scale_shape_manual(name = "Ecosystem",
                     values = c("warm" = 15, 
                                "cool" = 16, 
                                "cold" = 17)) +
  scale_alpha_manual(values = c("2001" = 1,
                                "2009" = 0.6,
                                "2019" = 0.3)) +
  scale_linetype_manual(values = c("2001" = "solid",
                                   "2009" = "dashed",
                                   "2019" = "dotted")) +
  facet_grid(rows = vars(eco), cols = vars(pm)) +
  xlab(expression(Delta*''^14*'C (‰)')) +
  ylab("Depth (cm)") +
  theme_bw() +
  theme(panel.grid.minor = element_blank())

Fig. 16. Time series of bulk soil \(\Delta\)14C by depth (splined to 2019 depths)

Caption: Points for 2019 samples show the mean \(\Delta\)14C values at the measured depths. Points for 2001 and 2009 samples are spline-fitted estimates of \(\Delta\)14C predicted for the same depth intervals as measured in 2019. Error bars show ± 1 standard deviation of the mean of three replicate profiles for 2001 and 2019 samples (only a single profile was analyzed in 2009). NB: Only two depth intervals were measured at the cool and cold andesite sites (max depth of 27 and 28 cm, respectively), so linear extrapolation (using the slope of the last 1cm spline-fitted depth increment) was used to extend the profiles to 30 cm.

# plot individual depths
fig.n <- fig.n + 1

# Atm
atm.14c <- data.frame(year = Datm[Datm$Date > 2000, "Date"],
                      d14c = Datm[Datm$Date > 2000, "NHc14"])
save(atm.14c, file = "atm.14c.RData")

# bulk 14C over time for 0-10, 10-20, 20-30 w/ atm
sra.19.01.09 %>%
  filter(lyr_bot < 31) %>%
  mutate(PMeco_depth = paste0(PMeco, lyr_bot),
         depth = factor(lyr_bot),
         eco = factor(ifelse(ECO == "pp", "warm",
                      ifelse(ECO == "wf", "cool", "cold")),
                      levels = c("warm", "cool", "cold")),
         d14c_u = d14c + d14c_sd,
         d14c_l = d14c - d14c_sd,
         pm = ifelse(PM == "AN", "andesite",
                     ifelse(PM == "BS", "basalt", "granite")),
         year = as.numeric(as.character(Year))) %>%
  ggplot(., aes(year, d14c)) +
  geom_path(data = atm.14c) +
  geom_point(aes(color = pm, shape = eco), size = 3) +
  geom_path(aes(color = pm, group = PMeco_depth, linetype = depth), alpha = 0.3) +
  geom_errorbar(
    aes(ymin = d14c_l, 
        ymax = d14c_u,
        color = pm), 
    width = .5) +
  scale_color_manual(name = "Parent material",
                     values = c("andesite" = "blue", 
                                "basalt" = "red", 
                                "granite" = "darkgray")) +
  scale_shape_manual(name = "Ecosystem",
                     values = c("warm" = 15, 
                                "cool" = 16, 
                                "cold" = 17)) +
  scale_linetype_manual(name = "Depth (cm)",
                        labels = c("10" = "0-10",
                                   "20" = "10-20",
                                   "30" = "20-30"),
                        values = c("10" = 1,
                                   "20" = 2,
                                   "30" = 3)) +
  facet_grid(rows = vars(eco), cols = vars(pm)) +
  ylab(expression(Delta*''^14*'C (‰)')) +
  xlab("Year") +
  theme_bw() +
  theme(panel.grid = element_blank())


### incubation
## 2019
sra.2019.inc.df <- bind_rows(lapply(sra.2019.inc.ls, function(df) {
  data.frame(df %>%
               group_by(Year, PM, ECO, lyr_bot, PMeco) %>%
               summarize(
                 across(.cols = d14c, 
                        .fns = list(mean = mean, min = min, max = max))) %>%
               rename(year = Year, d14c = d14c_mean))
}))
save(sra.2019.inc.df, file = "sra.2019.inc.df.RData")
## 2001
sra.19.01.inc.df <- bind_rows(lapply(seq_along(sra.19.01.inc.ls), function(i) {
  PMeco <- names(sra.19.01.inc.ls)[i]
  d14c.ls <- lapply(sra.19.01.inc.ls[[i]], calc_14c, obs_date_y = 2001)
  df <- data.frame(d14c = d14c.ls[[1]],
                   d14c_min = d14c.ls[[2]],
                   d14c_max = d14c.ls[[3]],
                   lyr_bot = c(10, 20, 30),
                   PMeco = PMeco,
                   PM = substr(PMeco, 1, 2),
                   ECO = substr(PMeco, 3, 4),
                   year = 2001)
  return(df)
}))
# join
sra.19.01.inc <- rbind(sra.19.01.inc.df, sra.2019.inc.df)

# plot
sra.19.01.inc %>%
  mutate(PMeco_depth = paste0(PMeco, lyr_bot),
         depth = factor(lyr_bot),
         eco = factor(ifelse(ECO == "pp", "warm",
                      ifelse(ECO == "wf", "cool", "cold")),
                      levels = c("warm", "cool", "cold")),
         pm = ifelse(PM == "AN", "andesite",
                     ifelse(PM == "BS", "basalt", "granite"))) %>%
  ggplot(., aes(year, d14c)) +
  geom_path(data = atm.14c) +
  geom_point(aes(color = eco, shape = eco), size = 3) +
  geom_point(data = sra.2019.inc.L.df, aes(color = eco), shape = 8, size = 3, show.legend = FALSE) +
  geom_path(aes(color = eco, group = PMeco), alpha = 0.3) +
  geom_errorbar(
    aes(ymin = d14c_min, 
        ymax = d14c_max,
        color = eco), 
    width = .5) +
  geom_errorbar(
    data = sra.2019.inc.L.df,
    aes(ymin = d14c_min, 
        ymax = d14c_max,
        color = eco), 
    width = .5) +
  scale_shape_manual(name = "Ecosystem",
                     values = c("warm" = 15, 
                                "cool" = 16, 
                                "cold" = 17)) +
  scale_y_continuous(limits = c(-40, 170)) +
  facet_grid(rows = vars(pm), cols = vars(depth)) +
  ylab(expression(Delta*''^14*'C (‰)')) +
  xlab("Year") +
  theme_bw() +
  theme(panel.grid = element_blank())


# plot inc and bulk together, by depth
sra.ts.all <- sra.19.01.09 %>%
  filter(lyr_bot < 31) %>%
  select(Year, PM, ECO, PMeco, lyr_bot, d14c, d14c_sd) %>%
  mutate(Type = "bulk",
         d14c_u = d14c + d14c_sd,
         d14c_l = d14c - d14c_sd,
         year = as.numeric(as.character(Year))) %>%
  select(-d14c_sd, -Year) %>%
  bind_rows(.,
            sra.19.01.inc %>%
              select(year, PM, ECO, PMeco, lyr_bot, d14c, d14c_min, d14c_max) %>%
              rename(d14c_l = d14c_min,
                     d14c_u = d14c_max) %>%
              mutate(Type = "inc")
  ) %>%
  mutate(depth = factor(lyr_bot),
         eco = factor(ifelse(ECO == "pp", "warm",
                      ifelse(ECO == "wf", "cool", "cold")),
                      levels = c("warm", "cool", "cold")),
         pm = ifelse(PM == "AN", "andesite",
                     ifelse(PM == "BS", "basalt", "granite")),
         ecoType = paste0(eco, " (", Type, ")"))

# Plot by depth
plot.ts.fx <- function(df) {
  df %>%
    filter(d14c > -200) %>%
    filter(year != 2009) %>%
    ggplot(., aes(year, d14c)) +
    geom_path(data = atm.14c) +
    geom_point(aes(color = pm, shape = ecoType), size = 3) +
    geom_path(aes(color = pm, linetype = Type), alpha = 0.3) +
    geom_errorbar(
      aes(ymin = d14c_l, 
          ymax = d14c_u,
          color = pm), 
      width = .5) +
    scale_color_manual(name = "Parent material",
                       values = c("andesite" = "blue", 
                                  "basalt" = "red", 
                                  "granite" = "darkgray")) +
    scale_shape_manual(name = "Ecosystem (type)",
                       values = c("warm (inc)" = 0,
                                  "cool (inc)" = 1,
                                  "cold (inc)" = 2,
                                  "warm (bulk)" = 15,
                                  "cool (bulk)" = 16,
                                  "cold (bulk)" = 17)) +
    facet_grid(rows = vars(eco), cols = vars(pm)) +
    ylab(expression(Delta*''^14*'C (‰)')) +
    xlab("Year") +
    theme_bw() +
    theme(panel.grid = element_blank())
}

# plots
lapply(split(sra.ts.all, sra.ts.all$depth), plot.ts.fx)
$`10`

$`20`

$`30`

# # to save
# for(i in 1:3) ggsave(paste0(i, ".pdf"), lapply(split(sra.ts.all, sra.ts.all$depth), plot.ts.fx)[[i]])

Fig. 16. Change in \(\Delta\)14C of bulk soil (panel a) and respired CO2 (panel b) over time relative to the atmosphere

Caption: Points for 2019 samples show the mean \(\Delta\)14C values at the measured depths. Points for 2001 and 2009 (bulk only) samples are spline-fitted estimates of \(\Delta\)14C predicted for the same depth intervals as measured in 2019. Error bars for bulk samples in panel (a) show ± 1 standard deviation of the mean of three replicate profiles for 2001 and 2019 samples (only a single profile was analyzed in 2009); error bars for incubation samples in panel (b) show the values of the two reps, while the point represents the mean. NB: Only two depth intervals were measured at the cool and cold andesite sites (max depth of 27 and 28 cm, respectively), so linear extrapolation (using the slope of the last 1cm spline-fitted depth increment) was used to extend the profiles to 30 cm.

# load data
ras18.frc <- read_excel("/Users/jeff/sra-ts/data/external/sra_ras_sum/sierra_data_summary_2020.xlsx",
                        sheet = "2009_fraction_data")

# select only min cols and pivot longer
ras18_2 <- ras18.sum %>%
  select(`Fed (g/kg)`, `Feo (g/kg)`, `Alo (g/kg)`, `Alp (g/kg)`, `top mineral`, `bottom mineral`, pro_name) %>% 
  rename(lyr_top = `top mineral`,
         lyr_bot = `bottom mineral`) %>%
  pivot_longer(cols = c(`Fed (g/kg)`, 
                        `Feo (g/kg)`, 
                        `Alo (g/kg)`, 
                        `Alp (g/kg)`), 
               names_to = "mins", values_to = "conc") %>%
  data.frame()

# Calculate min stocks
ras18_3 <- ras18.sum %>%
  select(`Fed (g/kg)`, `Feo (g/kg)`, `Alo (g/kg)`, `Alp (g/kg)`, `top mineral`, `bottom mineral`, pro_name, BD_g_cm_3, Soil_finefraction, Thickness_cm) %>% 
  rename(lyr_top = `top mineral`,
         lyr_bot = `bottom mineral`) %>%
  pivot_longer(cols = c(`Fed (g/kg)`, 
                        `Feo (g/kg)`, 
                        `Alo (g/kg)`, 
                        `Alp (g/kg)`), 
               names_to = "mins", values_to = "conc") %>%
  mutate(mass = Thickness_cm * BD_g_cm_3 * Soil_finefraction * 10,
         min_stock = conc * mass * 10^-2) %>%
  data.frame()
ras18_3.ls <- lapply(split(ras18_3, ras18_3$mins), function(df) {
  lapply(split(df, df$pro_name), function(x) {
    x <- x[order(x$lyr_bot), ]
    # calc cmtv min stock
    x$min_stock_cmtv <- NA
    for(i in seq_along(x$lyr_bot)) {
      if(i == 1) {
        x$min_stock_cmtv[i] <- x$min_stock[i]
      } else {
        x$min_stock_cmtv[i] <- x$min_stock[i] + x$min_stock_cmtv[i-1] 
      }
    }
    x$mass_cmtv <- NA
    for(i in seq_along(x$lyr_bot)) {
      if(i == 1) {
        x$mass_cmtv[i] <- x$mass[i]
      } else {
        x$mass_cmtv[i] <- x$mass[i] + x$mass_cmtv[i-1] 
      }
    }
    return(x)
  })
})
ras18_3.sp.df <- bind_rows(lapply(ras18_3.ls, function(ls) {
  bind_rows(lapply(ls, function(x) {
    depths(x) <- pro_name ~ lyr_top + lyr_bot
    x.mps <- mpspline(x, var.name = "min_stock_cmtv")
    return(x.mps$var.1cm[30])
  }), .id = "pro_name") %>%
    pivot_longer(cols = everything(), names_to = "pro_name", values_to = "min_stock_cmtv")
}), .id = "min") %>%
  mutate(min = ifelse(min == "Alo (g/kg)", "Al_ox",
                      ifelse(min == "Alp (g/kg)", "Al_py",
                             ifelse(min == "Fed (g/kg)", "Fe_dc", "Fe_ox"))),
         PMeco = substr(pro_name, 1, 4)) %>%
  select(-pro_name)
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
# mass-weighted concentration
ras18_4.sp.ls <- lapply(ras18_3.ls, function(ls) {
  conc <- unlist(lapply(ls, function(x) {
    depths(x) <- pro_name ~ lyr_top + lyr_bot
    x.mps <- mpspline(x, var.name = "conc")
    df <- data.frame(conc = x.mps$var.1cm[1:30],
                     lyr_bot = seq(1, 30),
                     pro_name = substr(x.mps$idcol, 1, 4))
    return(split(df, df$pro_name))
    }), recursive = FALSE)
  mass <- unlist(lapply(seq_along(ls), function(i) {
    x <- ls[[i]][ , c("lyr_bot", "mass_cmtv")]
    t0 <- data.frame(matrix(nrow = 1, ncol = ncol(x)))
    names(t0) <- names(x)
    t0 <- 0
    x <- rbind(t0, x)
    sp <- spline(x, method = "hyman") # fit monotonic cubic spline
    sp.ss <- smooth.spline(sp) # convert to class "spline" with smooth.spline fxn
    std <- seq(0, 30) # depth in cm
    sp <- predict(sp.ss, std) 
    df <- data.frame(sp)
    colnames(df) <- c("lyr_bot", "mass_cmtv")
    df$pro_name <- substr(names(ls)[i], 1, 4)
    df <- df[-1, ]
    return(split(df, df$pro_name))
  }), recursive = FALSE)
  return(mapply(merge,
                mass,
                conc,
                SIMPLIFY = FALSE))
})
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
# calculate mass-weighted conc for 0-30cm
ras18_4.sp.df <- bind_rows(lapply(ras18_4.sp.ls, function(ls) {
  bind_rows(lapply(ls, function(df) {
    df <- df[order(df$lyr_bot), ]
    df$mass <- NA
    for (i in seq_along(df$mass)) {
      if (i == 1) {
        df$mass[i] <- df$mass_cmtv[i]
      } else {
        df$mass[i] <- df$mass_cmtv[i] - df$mass_cmtv[i-1]
      }
    }
    df$mass_wt <- df$mass/sum(df$mass)
    df$conc_30_wtd <- df$mass_wt * df$conc
    return(sum(df$conc_30_wtd))
  }), .id = "pro_name")
}), .id = "min") %>%
  pivot_longer(!min, names_to = "PMeco", values_to = "conc") %>%
  mutate(min = ifelse(min == "Alo (g/kg)", "Al_ox", 
                      ifelse(min == "Alp (g/kg)", "Al_py",
                             ifelse(min == "Fed (g/kg)", "Fe_dc", "Fe_ox"))))

# merge w/ 14C data
sra.all.30.min.conc.wtd <- merge(sra.30.blk.inc.df, ras18_4.sp.df, by = "PMeco") %>%
  mutate(pm = ifelse(substr(PMeco, 1, 2) == "AN", "andesite", 
                     ifelse(substr(PMeco, 1, 2) == "BS", "basalt", "granite")),
         eco = ifelse(substr(PMeco, 3, 4) == "pp", "warm", 
                      ifelse(substr(PMeco, 3, 4) == "wf", "cool", "cold")))
save(sra.all.30.min.conc.wtd, file = "sra.all.30.min.conc.wtd.RData")

# spline fits
# (should be mass-weighted...)
# also calculate for 0-30cm
ras18.split <- split(ras18_2, ras18_2$mins)
ras18.sp <- lapply(ras18.split, function(df) {
  ls <- lapply(split(df, df$pro_name), function(x) {
    depths(x) <- pro_name ~ lyr_top + lyr_bot
    x.mps <- mpspline(x, var.name = "conc", d = t(seq(0, 100, 10)))
    return(x.mps$var.std)
  })
  names(ls) <- unique(df$pro_name)
  return(ls)
})
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
Fitting mass preserving splines per profile...

  |                                                                                               
  |                                                                                         |   0%
  |                                                                                               
  |=========================================================================================| 100%
names(ras18.sp) <- c("Al_ox", "Al_py", "Fe_dc", "Fe_ox")
ras18.sp.df <- data.frame(reduce(lapply(seq_along(ras18.sp), function(i) {
    df <- data.frame(t(bind_rows(ras18.sp[[i]])))
    names(df) <- unique(ras18.sum$pro_name)
    df$depth <- rownames(df)
    return(df %>%
             pivot_longer(!depth, names_to = "pro_name", values_to = names(ras18.sp)[i]))
  }),
  left_join,
  by = c("depth", "pro_name")
))
ras18.sp.df <- ras18.sp.df[-which(ras18.sp.df$depth == "soil depth"), ]
ras18.sp.df$lyr_bot <- rep(seq(10, 100, 10), each = 9)
ras18.sp.df <- ras18.sp.df[complete.cases(ras18.sp.df), ]
ras18.sp.df$PM <- substr(ras18.sp.df$pro_name, 1, 2)
ras18.sp.df$ECO <- substr(ras18.sp.df$pro_name, 3, 4)
save(ras18.sp.df, file = "ras18.sp.df.RData")

# reshape sra.ts.all w/ bulk and inc in separate cols
nms.inc.blk2 <- nms.inc.blk
nms.inc.blk2[[4]] <- "year"
sra.ts.all.blk.inc <- merge(sra.ts.all[sra.ts.all$Type == "bulk", ],
                            sra.ts.all[sra.ts.all$Type == "inc", c(nms.inc.blk2, "d14c", "d14c_u", "d14c_l")],
                            by = nms.inc.blk2,
                            suffixes = c("_bulk", "_inc")) %>%
  filter(year != 2009) %>%
  mutate(blk.inc = d14c_bulk - d14c_inc,
         blk.inc.sd = sqrt((d14c_u_bulk - d14c_bulk)^2 + apply(cbind(d14c_u_inc, d14c_l_inc), 1, var)))

# join w/ d14c
sra.all.min <- ras18.sp.df %>%
  mutate(pm = ifelse(PM == "AN", "andesite", ifelse(PM == "BS", "basalt", "granite")),
         eco = ifelse(ECO == "pp", "warm", ifelse(ECO == "wf", "cool", "cold"))) %>%
  # mutate(Al_nonCrys = Al_ox - Al_py,
  #        Fe_Crys = Fe_dc - Fe_ox) %>%
  select(-PM, -ECO, -pro_name) %>%
  left_join(sra.ts.all.blk.inc[ , c("pm", "eco", "lyr_bot", "year", "d14c_bulk", "d14c_u_bulk", "d14c_inc", "d14c_u_inc", "d14c_l_inc", "d14c_l_bulk", "blk.inc", "blk.inc.sd")], 
            ., 
            by = c("pm", "eco", "lyr_bot")) %>%
  pivot_longer(cols = c("Al_py", "Al_ox", "Fe_ox", "Fe_dc", 
                        # "Al_nonCrys", "Fe_Crys"
                        ), names_to = "min", values_to = "conc")

# Create min/14c df w/ 0-30cm 14C data
sra.all.30.min <- merge(sra.30.blk.inc.df, ras18_3.sp.df, by = "PMeco") %>%
  mutate(pm = ifelse(substr(PMeco, 1, 2) == "AN", "andesite", 
                     ifelse(substr(PMeco, 1, 2) == "BS", "basalt", "granite")),
         eco = ifelse(substr(PMeco, 3, 4) == "pp", "warm", 
                      ifelse(substr(PMeco, 3, 4) == "wf", "cool", "cold")))


# save
save(sra.all.min, file = "sra.all.min.RData")
save(sra.all.30.min, file = "sra.all.30.min.RData")
# bulk
sra.all.min %>%
  mutate(pmEcoDepth = paste0(pm, eco, lyr_bot),
         ecoYear = paste0(eco, " (", year, ")"),
         width = ifelse(min == "Al_py" | min == "Fe_ox", .3, 1.5)) %>%
  filter(pmEcoDepth != "granitecold30" & pmEcoDepth != "granitecold20") %>%
  ggplot(., aes(conc, d14c_bulk)) +
  geom_point(aes(color = pm, shape = ecoYear, size = depth)) +
  geom_errorbar(
    aes(ymin = d14c_l_bulk,
        ymax = d14c_u_bulk,
        color = pm,
        width = width)) +
  scale_color_manual(name = "Parent material",
                     values = c("andesite" = andesite,
                                "basalt" = basalt,
                                "granite" = granite)) +
  scale_shape_manual(name = "Climate (year)",
                     values = c("warm (2001)" = 15, 
                                "cool (2001)" = 16, 
                                "cold (2001)" = 17,
                                "warm (2019)" = 0, 
                                "cool (2019)" = 1, 
                                "cold (2019)" = 2)) +
  scale_size_manual(name = "Depth",
                    values = (3:5)) +
  facet_wrap(vars(min), scales = "free") +
  ylab(expression('Bulk - Respired '*Delta*''^14*'C (‰)')) +
  xlab(expression('Concentration (g kg'^-1*')')) +
  theme_bw() +
  theme(panel.grid.minor = element_blank())


# inc
sra.all.min %>%
  mutate(pmEcoDepth = paste0(pm, eco, lyr_bot),
         ecoYear = paste0(eco, " (", year, ")"),
         width = ifelse(min == "Al_py" | min == "Fe_ox", .3, 1.5)) %>%
  filter(pmEcoDepth != "granitecold30" & pmEcoDepth != "granitecold20") %>%
  filter(lyr_bot == 30) %>%
  ggplot(., aes(conc, d14c_inc)) +
  geom_point(aes(color = pm, shape = ecoYear, size = depth)) +
  geom_errorbar(
    aes(ymin = d14c_l_inc,
        ymax = d14c_u_inc,
        color = pm,
        width = width)) +
  scale_color_manual(name = "Parent material",
                     values = c("andesite" = andesite,
                                "basalt" = basalt,
                                "granite" = granite)) +
  scale_shape_manual(name = "Climate (year)",
                     values = c("warm (2001)" = 15, 
                                "cool (2001)" = 16, 
                                "cold (2001)" = 17,
                                "warm (2019)" = 0, 
                                "cool (2019)" = 1, 
                                "cold (2019)" = 2)) +
  scale_size_manual(name = "Depth",
                    values = (3:5)) +
  facet_wrap(vars(min), scales = "free") +
  ylab(expression('Bulk - Respired '*Delta*''^14*'C (‰)')) +
  xlab(expression('Concentration (g kg'^-1*')')) +
  theme_bw() +
  theme(panel.grid.minor = element_blank())


# bulk-inc
sra.all.min %>%
  mutate(pmEcoDepth = paste0(pm, eco, lyr_bot),
         ecoYear = paste0(eco, " (", year, ")"),
         width = ifelse(min == "Al_py" | min == "Fe_ox", .3, 1.5)) %>%
  filter(pmEcoDepth != "granitecold30" & pmEcoDepth != "granitecold20") %>%
  ggplot(., aes(conc, blk.inc)) +
  geom_point(aes(color = pm, shape = ecoYear, size = depth)) +
  geom_errorbar(
    aes(ymin = blk.inc - blk.inc.sd,
        ymax = blk.inc + blk.inc.sd,
        color = pm,
        width = width)) +
  scale_color_manual(name = "Parent material",
                     values = c("andesite" = andesite,
                                "basalt" = basalt,
                                "granite" = granite)) +
  scale_shape_manual(name = "Climate (year)",
                     values = c("warm (2001)" = 15, 
                                "cool (2001)" = 16, 
                                "cold (2001)" = 17,
                                "warm (2019)" = 0, 
                                "cool (2019)" = 1, 
                                "cold (2019)" = 2)) +
  scale_size_manual(name = "Depth",
                    values = (3:5)) +
  facet_wrap(vars(min), scales = "free") +
  ylab(expression('Bulk - Respired '*Delta*''^14*'C (‰)')) +
  xlab(expression('Concentration (g kg'^-1*')')) +
  theme_bw() +
  theme(panel.grid.minor = element_blank())


# Fe_dc alone
#####
# warm
sra.all.min %>%
  filter(eco == "warm" & min == "Fe_dc") %>%
  mutate(ecoYear = paste0(eco, " (", year, ")")) %>%
  ggplot(., aes(conc, blk.inc)) +
  geom_point(aes(color = pm, shape = ecoYear, size = depth)) +
  geom_errorbar(
    aes(ymin = blk.inc - blk.inc.sd,
        ymax = blk.inc + blk.inc.sd,
        color = pm),
        width = 1.5) +
  scale_color_manual(name = "Parent material",
                     values = c("andesite" = andesite,
                                "basalt" = basalt,
                                "granite" = granite)) +
  scale_shape_manual(name = "Climate (year)",
                     values = c("warm (2001)" = 15,
                                "warm (2019)" = 0)) +
  scale_size_manual(name = "Depth",
                    values = (3:5)) +
  facet_wrap(vars(min), scales = "free") +
  ylab(expression('Bulk - Respired '*Delta*''^14*'C (‰)')) +
  xlab(expression('Concentration (g kg'^-1*')')) +
  theme_bw() +
  theme(panel.grid.minor = element_blank())


# cool + cold
sra.all.min %>%
  filter(eco != "warm" & min == "Fe_dc") %>%
  mutate(pmEcoDepth = paste0(pm, eco, lyr_bot),
         ecoYear = paste0(eco, " (", year, ")")) %>%
  filter(pmEcoDepth != "granitecold30" & pmEcoDepth != "granitecold20") %>%
  ggplot(., aes(conc, blk.inc)) +
  geom_point(aes(color = pm, shape = ecoYear, size = depth)) +
  geom_errorbar(
    aes(ymin = blk.inc - blk.inc.sd,
        ymax = blk.inc + blk.inc.sd,
        color = pm),
        width = .5) +
  scale_color_manual(name = "Parent material",
                     values = c("andesite" = andesite,
                                "basalt" = basalt,
                                "granite" = granite)) +
  scale_shape_manual(name = "Climate (year)",
                     values = c("cool (2001)" = 16, 
                                "cold (2001)" = 17,
                                "cool (2019)" = 1, 
                                "cold (2019)" = 2)) +
  scale_size_manual(name = "Depth",
                    values = (3:5)) +
  facet_wrap(vars(min), scales = "free") +
  ylab(expression('Bulk - Respired '*Delta*''^14*'C (‰)')) +
  xlab(expression('Concentration (g kg'^-1*')')) +
  theme_bw() +
  theme(panel.grid.minor = element_blank())

#####

## by depth
#####
# # 10 cm
# sra.all.min %>%
#   mutate(ecoYear = paste0(eco, " (", year, ")"),
#          width = ifelse(min == "Al_py" | min == "Fe_ox", .3, 1.5)) %>%
#   filter(lyr_bot == 10) %>%
#   ggplot(., aes(conc, blk.inc)) +
#   geom_point(aes(color = pm, shape = ecoYear), size = 3) +
#   geom_errorbar(
#     aes(ymin = blk.inc - blk.inc.sd,
#         ymax = blk.inc + blk.inc.sd,
#         color = pm,
#         width = width)) +
#   scale_color_manual(name = "Parent material",
#                      values = c("andesite" = andesite,
#                                 "basalt" = basalt,
#                                 "granite" = granite)) +
#   scale_shape_manual(name = "Climate (year)",
#                      values = c("warm (2001)" = 15, 
#                                 "cool (2001)" = 16, 
#                                 "cold (2001)" = 17,
#                                 "warm (2019)" = 0, 
#                                 "cool (2019)" = 1, 
#                                 "cold (2019)" = 2)) +
#   facet_wrap(vars(min), scales = "free") +
#   ylab(expression('Bulk - Respired '*Delta*''^14*'C (‰)')) +
#   xlab(expression('Concentration (g kg'^-1*')')) +
#   theme_bw() +
#   theme(panel.grid.minor = element_blank())
# 
# # 20 cm
# sra.all.min %>%
#   mutate(pmEcoDepth = paste0(pm, eco, lyr_bot),
#          ecoYear = paste0(eco, " (", year, ")"),
#          width = ifelse(min == "Al_py" | min == "Fe_ox", .3, 1.5)) %>%
#   filter(pmEcoDepth != "granitecold20") %>%
#   filter(lyr_bot == 20) %>%
#   ggplot(., aes(conc, blk.inc)) +
#   geom_point(aes(color = pm, shape = ecoYear), size = 3) +
#   geom_errorbar(
#     aes(ymin = blk.inc - blk.inc.sd,
#         ymax = blk.inc + blk.inc.sd,
#         color = pm,
#         width = width)) +
#   scale_color_manual(name = "Parent material",
#                      values = c("andesite" = andesite,
#                                 "basalt" = basalt,
#                                 "granite" = granite)) +
#   scale_shape_manual(name = "Climate (year)",
#                      values = c("warm (2001)" = 15, 
#                                 "cool (2001)" = 16, 
#                                 "cold (2001)" = 17,
#                                 "warm (2019)" = 0, 
#                                 "cool (2019)" = 1, 
#                                 "cold (2019)" = 2)) +
#   facet_wrap(vars(min), scales = "free") +
#   ylab(expression('Bulk - Respired '*Delta*''^14*'C (‰)')) +
#   xlab(expression('Concentration (g kg'^-1*')')) +
#   theme_bw() +
#   theme(panel.grid.minor = element_blank())
# 
# # 30 cm
# sra.all.min %>%
#   mutate(pmEcoDepth = paste0(pm, eco, lyr_bot),
#          ecoYear = paste0(eco, " (", year, ")"),
#          width = ifelse(min == "Al_py" | min == "Fe_ox", .3, 1.5)) %>%
#   filter(pmEcoDepth != "granitecold30") %>%
#   filter(lyr_bot == 30) %>%
#   ggplot(., aes(conc, blk.inc)) +
#   geom_point(aes(color = pm, shape = ecoYear), size = 3) +
#   geom_errorbar(
#     aes(ymin = blk.inc - blk.inc.sd,
#         ymax = blk.inc + blk.inc.sd,
#         color = pm,
#         width = width)) +
#   scale_color_manual(name = "Parent material",
#                      values = c("andesite" = andesite,
#                                 "basalt" = basalt,
#                                 "granite" = granite)) +
#   scale_shape_manual(name = "Climate (year)",
#                      values = c("warm (2001)" = 15, 
#                                 "cool (2001)" = 16, 
#                                 "cold (2001)" = 17,
#                                 "warm (2019)" = 0, 
#                                 "cool (2019)" = 1, 
#                                 "cold (2019)" = 2)) +
#   facet_wrap(vars(min), scales = "free") +
#   ylab(expression('Bulk - Respired '*Delta*''^14*'C (‰)')) +
#   xlab(expression('Concentration (g kg'^-1*')')) +
#   theme_bw() +
#   theme(panel.grid.minor = element_blank())
# function for Tukey HSD tables
tukey.table.fx <- function(x, year, type, var) {
  depth <- paste0(unique(x$lyr_bot) - 10, "-", unique(x$lyr_bot), " cm")
  if (type == "inc") {
    x <- x[x$d14c > -200, c("d14c", var)]
  } 
  return(
    TukeyHSD(aov(reformulate(var, "d14c"), x))[var] %>%
    data.frame(.) %>%
    mutate(Pairs = rownames(.)) %>%
    mutate(across(where(is.numeric), round, 3)) %>%
    gt() %>%
    tab_header(
      title = depth,
      subtitle = paste(year, type, var)
    ))
}

### 2001
## bulk
sra.2001.bulk.df <- bind_rows(
  lapply(sra.19.01.rep.ls, function(ls) {
    ls <- lapply(ls, function(x) x[complete.cases(x)])
    d14c <- calc_14c(unlist(ls), 2001)
    df <- data.frame(d14c = d14c,
                     lyr_bot = rep(c(10, 20, 30), length(d14c) / 3))
    return(df)
  }),
  .id = "PMeco") %>%
  mutate(PM = substr(PMeco, 1, 2),
         ECO = substr(PMeco, 3, 4))
# PM
# lapply(split(sra.2001.bulk.df, sra.2001.bulk.df$lyr_bot), function(x) {
#   summary(lm(d14c ~ PM, x))
# })
lapply(split(sra.2001.bulk.df, sra.2001.bulk.df$lyr_bot), function(x) {
  tukey.table.fx(x, "2001", "bulk", "PM")
})
$`10`
0-10 cm
2001 bulk PM
PM.diff PM.lwr PM.upr PM.p.adj Pairs
3.776 -57.040 64.592 0.987 BS-AN
43.034 -17.782 103.850 0.201 GR-AN
39.258 -19.742 98.258 0.239 GR-BS

$`20`
10-20 cm
2001 bulk PM
PM.diff PM.lwr PM.upr PM.p.adj Pairs
47.757 4.712 90.803 0.028 BS-AN
45.292 2.247 88.338 0.038 GR-AN
-2.465 -44.225 39.295 0.988 GR-BS

$`30`
20-30 cm
2001 bulk PM
PM.diff PM.lwr PM.upr PM.p.adj Pairs
55.395 17.734 93.055 0.003 BS-AN
66.204 28.544 103.865 0.001 GR-AN
10.810 -25.726 47.346 0.742 GR-BS
# ECO
# lapply(split(sra.2001.bulk.df, sra.2001.bulk.df$lyr_bot), function(x) {
#   summary(lm(d14c ~ ECO, x))
# })
lapply(split(sra.2001.bulk.df, sra.2001.bulk.df$lyr_bot), function(x) {
  tukey.table.fx(x, "2001", "bulk", "ECO")
})
$`10`
0-10 cm
2001 bulk ECO
ECO.diff ECO.lwr ECO.upr ECO.p.adj Pairs
-71.522 -121.112 -21.931 0.004 rf-pp
-69.488 -117.597 -21.379 0.004 wf-pp
2.033 -47.557 51.623 0.994 wf-rf

$`20`
10-20 cm
2001 bulk ECO
ECO.diff ECO.lwr ECO.upr ECO.p.adj Pairs
-30.492 -77.815 16.831 0.260 rf-pp
-33.125 -79.035 12.785 0.190 wf-pp
-2.633 -49.956 44.690 0.989 wf-rf

$`30`
20-30 cm
2001 bulk ECO
ECO.diff ECO.lwr ECO.upr ECO.p.adj Pairs
-19.910 -71.507 31.686 0.605 rf-pp
-9.482 -59.538 40.574 0.884 wf-pp
10.429 -41.168 62.025 0.869 wf-rf
## inc
sra.2001.inc.df2 <- cbind(sra.19.01.inc.df[rep(1:nrow(sra.19.01.inc.df), 2), c("PM", "ECO", "lyr_bot")],
                          d14c = c(sra.19.01.inc.df$d14c_min, sra.19.01.inc.df$d14c_max))
save(sra.2001.inc.df2, file = "sra.2001.inc.df2.RData")
# PM
# lapply(split(sra.2001.inc.df2, sra.2001.inc.df2$lyr_bot), function(x) {
#   summary(lm(d14c ~ PM, x[x$d14c > -200, ]))
# })
lapply(split(sra.2001.inc.df2, sra.2001.inc.df2$lyr_bot), function(x) {
  tukey.table.fx(x, "2001", "inc", "PM")
})
$`10`
0-10 cm
2001 inc PM
PM.diff PM.lwr PM.upr PM.p.adj Pairs
-8.178 -63.772 47.417 0.923 BS-AN
-3.095 -58.689 52.500 0.989 GR-AN
5.083 -50.512 60.678 0.969 GR-BS

$`20`
10-20 cm
2001 inc PM
PM.diff PM.lwr PM.upr PM.p.adj Pairs
23.755 -39.544 87.055 0.600 BS-AN
-44.282 -110.671 22.108 0.224 GR-AN
-68.037 -134.426 -1.648 0.044 GR-BS

$`30`
20-30 cm
2001 inc PM
PM.diff PM.lwr PM.upr PM.p.adj Pairs
41.442 -56.220 139.105 0.523 BS-AN
-61.708 -164.138 40.721 0.288 GR-AN
-103.151 -205.580 -0.721 0.048 GR-BS
# ECO
# lapply(split(sra.2001.inc.df2, sra.2001.inc.df2$lyr_bot), function(x) {
#   summary(lm(d14c ~ ECO, x[x$d14c > -200, ]))
# })
lapply(split(sra.2001.inc.df2, sra.2001.inc.df2$lyr_bot), function(x) {
  tukey.table.fx(x, "2001", "inc", "ECO")
})
$`10`
0-10 cm
2001 inc ECO
ECO.diff ECO.lwr ECO.upr ECO.p.adj Pairs
-54.988 -96.644 -13.332 0.010 rf-pp
-34.104 -75.760 7.552 0.118 wf-pp
20.883 -20.773 62.539 0.416 wf-rf

$`20`
10-20 cm
2001 inc ECO
ECO.diff ECO.lwr ECO.upr ECO.p.adj Pairs
-21.298 -100.627 58.032 0.766 rf-pp
6.974 -68.664 82.612 0.968 wf-pp
28.272 -51.058 107.601 0.629 wf-rf

$`30`
20-30 cm
2001 inc ECO
ECO.diff ECO.lwr ECO.upr ECO.p.adj Pairs
8.875 -106.631 124.380 0.978 rf-pp
61.977 -48.153 172.107 0.333 wf-pp
53.103 -62.403 168.608 0.471 wf-rf
### 2019
## bulk
sra.2019.bulk.df <- bind_rows(sra.2019.ls)
# PM
# lapply(split(sra.2019.bulk.df, sra.2019.bulk.df$lyr_bot), function(x) {
#   if (nrow(x) == 27) summary(lm(d14c ~ PM, x[x$d14c > -200, ]))
# })
lapply(split(sra.2019.bulk.df, sra.2019.bulk.df$lyr_bot), function(x) {
  if (nrow(x) == 27) tukey.table.fx(x, "2019", "bulk", "PM")
})
$`10`
0-10 cm
2019 bulk PM
PM.diff PM.lwr PM.upr PM.p.adj Pairs
-41.756 -76.898 -6.613 0.018 AN-GR
-9.522 -44.665 25.621 0.779 BS-GR
32.233 -2.909 67.376 0.077 BS-AN

$`20`
10-20 cm
2019 bulk PM
PM.diff PM.lwr PM.upr PM.p.adj Pairs
-54.667 -106.932 -2.401 0.039 AN-GR
-16.478 -68.743 35.788 0.714 BS-GR
38.189 -14.077 90.455 0.183 BS-AN

$`30`
20-30 cm
2019 bulk PM
PM.diff PM.lwr PM.upr PM.p.adj Pairs
-35.544 -84.884 13.796 0.191 AN-GR
-25.789 -75.129 23.551 0.406 BS-GR
9.756 -39.584 59.096 0.875 BS-AN

$`40`
30-40 cm
2019 bulk PM
PM.diff PM.lwr PM.upr PM.p.adj Pairs
-31.478 -89.509 26.553 0.380 AN-GR
-19.733 -77.765 38.298 0.677 BS-GR
11.744 -46.287 69.776 0.869 BS-AN

$`50`
40-50 cm
2019 bulk PM
PM.diff PM.lwr PM.upr PM.p.adj Pairs
-46.722 -107.064 13.620 0.151 AN-GR
-27.589 -87.931 32.753 0.498 BS-GR
19.133 -41.209 79.475 0.712 BS-AN

$`60`
50-60 cm
2019 bulk PM
PM.diff PM.lwr PM.upr PM.p.adj Pairs
-9.289 -72.136 53.558 0.928 AN-GR
-7.044 -69.891 55.802 0.958 BS-GR
2.244 -60.602 65.091 0.996 BS-AN

$`70`
NULL

$`80`
NULL

$`90`
NULL
# ECO
# lapply(split(sra.2019.bulk.df, sra.2019.bulk.df$lyr_bot), function(x) {
#   if (nrow(x) == 27) summary(lm(d14c ~ ECO, x[x$d14c > -200, ]))
# })
lapply(split(sra.2019.bulk.df, sra.2019.bulk.df$lyr_bot), function(x) {
  if (nrow(x) == 27) tukey.table.fx(x, "2019", "bulk", "ECO")
})
$`10`
0-10 cm
2019 bulk ECO
ECO.diff ECO.lwr ECO.upr ECO.p.adj Pairs
-31.500 -65.613 2.613 0.074 wf-rf
14.222 -19.890 48.335 0.559 pp-rf
45.722 11.610 79.835 0.007 pp-wf

$`20`
10-20 cm
2019 bulk ECO
ECO.diff ECO.lwr ECO.upr ECO.p.adj Pairs
-35.556 -82.679 11.568 0.165 wf-rf
35.944 -11.179 83.068 0.159 pp-rf
71.500 24.376 118.624 0.002 pp-wf

$`30`
20-30 cm
2019 bulk ECO
ECO.diff ECO.lwr ECO.upr ECO.p.adj Pairs
-58.167 -94.986 -21.348 0.002 wf-rf
10.767 -26.052 47.586 0.748 pp-rf
68.933 32.114 105.752 0.000 pp-wf

$`40`
30-40 cm
2019 bulk ECO
ECO.diff ECO.lwr ECO.upr ECO.p.adj Pairs
-67.222 -107.865 -26.579 0.001 wf-rf
14.578 -26.065 55.221 0.648 pp-rf
81.800 41.157 122.443 0.000 pp-wf

$`50`
40-50 cm
2019 bulk ECO
ECO.diff ECO.lwr ECO.upr ECO.p.adj Pairs
-59.322 -105.522 -13.122 0.010 wf-rf
28.344 -17.855 74.544 0.294 pp-rf
87.667 41.467 133.866 0.000 pp-wf

$`60`
50-60 cm
2019 bulk ECO
ECO.diff ECO.lwr ECO.upr ECO.p.adj Pairs
-59.622 -114.836 -4.409 0.033 wf-rf
-27.478 -82.691 27.736 0.440 pp-rf
32.144 -23.069 87.358 0.330 pp-wf

$`70`
NULL

$`80`
NULL

$`90`
NULL
## inc
sra.2019.inc.df2 <- bind_rows(sra.2019.inc.ls)
save(sra.2019.inc.df2, file = "sra.2019.inc.df2.RData")
# PM
# lapply(split(sra.2019.inc.df2, sra.2019.inc.df2$lyr_bot), function(x) {
#   summary(lm(d14c ~ PM, x[x$d14c > -200, ]))
# })
lapply(split(sra.2019.inc.df2, sra.2019.inc.df2$lyr_bot), function(x) {
  tukey.table.fx(x, "2019", "inc", "PM")
})
$`10`
0-10 cm
2019 inc PM
PM.diff PM.lwr PM.upr PM.p.adj Pairs
-3.917 -40.999 33.165 0.959 BS-AN
7.583 -29.499 44.665 0.857 GR-AN
11.500 -25.582 48.582 0.705 GR-BS

$`20`
10-20 cm
2019 inc PM
PM.diff PM.lwr PM.upr PM.p.adj Pairs
-16.133 -76.600 44.333 0.768 BS-AN
-24.507 -87.925 38.911 0.582 GR-AN
-8.373 -71.791 55.045 0.937 GR-BS

$`30`
20-30 cm
2019 inc PM
PM.diff PM.lwr PM.upr PM.p.adj Pairs
-36.657 -86.659 13.346 0.170 BS-AN
-21.283 -68.959 26.392 0.490 GR-AN
15.373 -34.629 65.376 0.706 GR-BS
# ECO
# lapply(split(sra.2019.inc.df2, sra.2019.inc.df2$lyr_bot), function(x) {
#   summary(lm(d14c ~ ECO, x[x$d14c > -200, ]))
# })
lapply(split(sra.2019.inc.df2, sra.2019.inc.df2$lyr_bot), function(x) {
  tukey.table.fx(x, "2019", "inc", "ECO")
})
$`10`
0-10 cm
2019 inc ECO
ECO.diff ECO.lwr ECO.upr ECO.p.adj Pairs
-19.217 -54.416 15.983 0.357 rf-pp
-2.367 -37.566 32.833 0.983 wf-pp
16.850 -18.350 52.050 0.447 wf-rf

$`20`
10-20 cm
2019 inc ECO
ECO.diff ECO.lwr ECO.upr ECO.p.adj Pairs
-32.333 -87.289 22.623 0.303 rf-pp
-48.617 -101.015 3.782 0.071 wf-pp
-16.283 -71.239 38.673 0.724 wf-rf

$`30`
20-30 cm
2019 inc ECO
ECO.diff ECO.lwr ECO.upr ECO.p.adj Pairs
-14.457 -68.364 39.450 0.766 rf-pp
-21.933 -73.332 29.465 0.520 wf-pp
-7.477 -61.384 46.430 0.930 wf-rf
# compare 2001 and 2019
# bulk
sra.01.19.bulk.df <- data.frame(
  rbind(sra.2001.bulk.df, 
        sra.2019.bulk.df[, which(names(sra.2019.bulk.df) %in% names(sra.2001.bulk.df))]),
  year = as.factor(c(rep(2001, nrow(sra.2001.bulk.df)), rep(2019, nrow(sra.2019.bulk.df))))) %>%
  filter(lyr_bot < 31)
sra.01.19.bulk.ls <- split(sra.01.19.bulk.df, sra.01.19.bulk.df$PMeco)
lapply(sra.01.19.bulk.ls, function(df) {
  lapply(split(df, df$lyr_bot), function(x) {
    tukey.table.fx(x, paste0(unique(df$PMeco), " 2001 vs. 2019"), "bulk", "year")
  })
})
$ANpp
$ANpp$`10`
0-10 cm
ANpp 2001 vs. 2019 bulk year
year.diff year.lwr year.upr year.p.adj Pairs
-108.646 -161.123 -56.17 0.005 2019-2001

$ANpp$`20`
10-20 cm
ANpp 2001 vs. 2019 bulk year
year.diff year.lwr year.upr year.p.adj Pairs
-39.132 -121.572 43.307 0.258 2019-2001

$ANpp$`30`
20-30 cm
ANpp 2001 vs. 2019 bulk year
year.diff year.lwr year.upr year.p.adj Pairs
19.62 -60.937 100.178 0.536 2019-2001


$ANrf
$ANrf$`10`
0-10 cm
ANrf 2001 vs. 2019 bulk year
year.diff year.lwr year.upr year.p.adj Pairs
-39.662 -97.2 17.876 0.116 2019-2001

$ANrf$`20`
10-20 cm
ANrf 2001 vs. 2019 bulk year
year.diff year.lwr year.upr year.p.adj Pairs
-23.451 -62.372 15.471 0.151 2019-2001

$ANrf$`30`
20-30 cm
ANrf 2001 vs. 2019 bulk year
year.diff year.lwr year.upr year.p.adj Pairs
3.602 -44.344 51.548 0.826 2019-2001


$ANwf
$ANwf$`10`
0-10 cm
ANwf 2001 vs. 2019 bulk year
year.diff year.lwr year.upr year.p.adj Pairs
2.096 -54.912 59.104 0.924 2019-2001

$ANwf$`20`
10-20 cm
ANwf 2001 vs. 2019 bulk year
year.diff year.lwr year.upr year.p.adj Pairs
7.388 -22.778 37.553 0.534 2019-2001

$ANwf$`30`
20-30 cm
ANwf 2001 vs. 2019 bulk year
year.diff year.lwr year.upr year.p.adj Pairs
5.913 -13.918 25.744 0.454 2019-2001


$BSpp
$BSpp$`10`
0-10 cm
BSpp 2001 vs. 2019 bulk year
year.diff year.lwr year.upr year.p.adj Pairs
-34.257 -85.03 16.516 0.134 2019-2001

$BSpp$`20`
10-20 cm
BSpp 2001 vs. 2019 bulk year
year.diff year.lwr year.upr year.p.adj Pairs
-4.4 -43.862 35.063 0.772 2019-2001

$BSpp$`30`
20-30 cm
BSpp 2001 vs. 2019 bulk year
year.diff year.lwr year.upr year.p.adj Pairs
-16.345 -82.688 49.998 0.532 2019-2001


$BSrf
$BSrf$`10`
0-10 cm
BSrf 2001 vs. 2019 bulk year
year.diff year.lwr year.upr year.p.adj Pairs
14.282 -37.804 66.367 0.489 2019-2001

$BSrf$`20`
10-20 cm
BSrf 2001 vs. 2019 bulk year
year.diff year.lwr year.upr year.p.adj Pairs
-8.656 -67.505 50.193 0.704 2019-2001

$BSrf$`30`
20-30 cm
BSrf 2001 vs. 2019 bulk year
year.diff year.lwr year.upr year.p.adj Pairs
27.438 -46.279 101.155 0.36 2019-2001


$BSwf
$BSwf$`10`
0-10 cm
BSwf 2001 vs. 2019 bulk year
year.diff year.lwr year.upr year.p.adj Pairs
-36.239 -83.527 11.049 0.1 2019-2001

$BSwf$`20`
10-20 cm
BSwf 2001 vs. 2019 bulk year
year.diff year.lwr year.upr year.p.adj Pairs
-64.075 -115.738 -12.412 0.026 2019-2001

$BSwf$`30`
20-30 cm
BSwf 2001 vs. 2019 bulk year
year.diff year.lwr year.upr year.p.adj Pairs
-113.138 -153.195 -73.08 0.001 2019-2001


$GRpp
$GRpp$`10`
0-10 cm
GRpp 2001 vs. 2019 bulk year
year.diff year.lwr year.upr year.p.adj Pairs
-51.541 -120.524 17.443 0.107 2019-2001

$GRpp$`20`
10-20 cm
GRpp 2001 vs. 2019 bulk year
year.diff year.lwr year.upr year.p.adj Pairs
36.232 -32.197 104.661 0.215 2019-2001

$GRpp$`30`
20-30 cm
GRpp 2001 vs. 2019 bulk year
year.diff year.lwr year.upr year.p.adj Pairs
2.096 -49.559 53.75 0.916 2019-2001


$GRrf
$GRrf$`10`
0-10 cm
GRrf 2001 vs. 2019 bulk year
year.diff year.lwr year.upr year.p.adj Pairs
-4.878 -56.92 47.164 0.808 2019-2001

$GRrf$`20`
10-20 cm
GRrf 2001 vs. 2019 bulk year
year.diff year.lwr year.upr year.p.adj Pairs
9.203 -13.93 32.335 0.331 2019-2001

$GRrf$`30`
20-30 cm
GRrf 2001 vs. 2019 bulk year
year.diff year.lwr year.upr year.p.adj Pairs
6.556 -18.916 32.027 0.514 2019-2001


$GRwf
$GRwf$`10`
0-10 cm
GRwf 2001 vs. 2019 bulk year
year.diff year.lwr year.upr year.p.adj Pairs
-89.004 -114.543 -63.464 0.001 2019-2001

$GRwf$`20`
10-20 cm
GRwf 2001 vs. 2019 bulk year
year.diff year.lwr year.upr year.p.adj Pairs
-65.737 -141.304 9.829 0.073 2019-2001

$GRwf$`30`
20-30 cm
GRwf 2001 vs. 2019 bulk year
year.diff year.lwr year.upr year.p.adj Pairs
-65.759 -140.676 9.159 0.071 2019-2001
# by PM
lapply(split(sra.01.19.bulk.df, sra.01.19.bulk.df$PM), function(df) {
  lapply(split(df, df$lyr_bot), function(x) {
    tukey.table.fx(x, paste0(unique(df$PM), " 2001 vs. 2019"), "bulk", "year")
  })
})
$AN
$AN$`10`
0-10 cm
AN 2001 vs. 2019 bulk year
year.diff year.lwr year.upr year.p.adj Pairs
-47.196 -96.931 2.54 0.061 2019-2001

$AN$`20`
10-20 cm
AN 2001 vs. 2019 bulk year
year.diff year.lwr year.upr year.p.adj Pairs
-16.142 -50.009 17.725 0.326 2019-2001

$AN$`30`
20-30 cm
AN 2001 vs. 2019 bulk year
year.diff year.lwr year.upr year.p.adj Pairs
11.624 -21.346 44.594 0.464 2019-2001


$BS
$BS$`10`
0-10 cm
BS 2001 vs. 2019 bulk year
year.diff year.lwr year.upr year.p.adj Pairs
-18.738 -51.619 14.142 0.245 2019-2001

$BS$`20`
10-20 cm
BS 2001 vs. 2019 bulk year
year.diff year.lwr year.upr year.p.adj Pairs
-25.71 -57.388 5.967 0.105 2019-2001

$BS$`30`
20-30 cm
BS 2001 vs. 2019 bulk year
year.diff year.lwr year.upr year.p.adj Pairs
-34.015 -76.337 8.307 0.108 2019-2001


$GR
$GR$`10`
0-10 cm
GR 2001 vs. 2019 bulk year
year.diff year.lwr year.upr year.p.adj Pairs
-48.474 -89.466 -7.482 0.023 2019-2001

$GR$`20`
10-20 cm
GR 2001 vs. 2019 bulk year
year.diff year.lwr year.upr year.p.adj Pairs
-6.768 -59.155 45.62 0.788 2019-2001

$GR$`30`
20-30 cm
GR 2001 vs. 2019 bulk year
year.diff year.lwr year.upr year.p.adj Pairs
-19.036 -54.623 16.551 0.274 2019-2001
# by ECO
lapply(split(sra.01.19.bulk.df, sra.01.19.bulk.df$ECO), function(df) {
  lapply(split(df, df$lyr_bot), function(x) {
    tukey.table.fx(x, paste0(unique(df$ECO), " 2001 vs. 2019"), "bulk", "year")
  })
})
$pp
$pp$`10`
0-10 cm
pp 2001 vs. 2019 bulk year
year.diff year.lwr year.upr year.p.adj Pairs
-64.815 -100.543 -29.086 0.001 2019-2001

$pp$`20`
10-20 cm
pp 2001 vs. 2019 bulk year
year.diff year.lwr year.upr year.p.adj Pairs
-2.433 -50.649 45.783 0.916 2019-2001

$pp$`30`
20-30 cm
pp 2001 vs. 2019 bulk year
year.diff year.lwr year.upr year.p.adj Pairs
1.79 -36.185 39.766 0.922 2019-2001


$rf
$rf$`10`
0-10 cm
rf 2001 vs. 2019 bulk year
year.diff year.lwr year.upr year.p.adj Pairs
-7.515 -30.699 15.668 0.5 2019-2001

$rf$`20`
10-20 cm
rf 2001 vs. 2019 bulk year
year.diff year.lwr year.upr year.p.adj Pairs
-7.886 -35.016 19.245 0.545 2019-2001

$rf$`30`
20-30 cm
rf 2001 vs. 2019 bulk year
year.diff year.lwr year.upr year.p.adj Pairs
10.934 -15.022 36.89 0.383 2019-2001


$wf
$wf$`10`
0-10 cm
wf 2001 vs. 2019 bulk year
year.diff year.lwr year.upr year.p.adj Pairs
-41.049 -84.594 2.497 0.063 2019-2001

$wf$`20`
10-20 cm
wf 2001 vs. 2019 bulk year
year.diff year.lwr year.upr year.p.adj Pairs
-40.808 -80.859 -0.757 0.046 2019-2001

$wf$`30`
20-30 cm
wf 2001 vs. 2019 bulk year
year.diff year.lwr year.upr year.p.adj Pairs
-57.661 -102.561 -12.761 0.015 2019-2001
# inc
sra.01.19.inc.df <- data.frame(
  d14c = c(sra.19.01.inc[ , "d14c_min"],
           sra.19.01.inc[ , "d14c_max"]),
  sra.19.01.inc[ , c("PMeco", "lyr_bot", "PM", "ECO", "year")]) %>%
  mutate(year = as.factor(year))
sra.01.19.inc.ls <- split(sra.01.19.inc.df, sra.01.19.inc.df$PMeco)
lapply(sra.01.19.inc.ls, function(df) {
  lapply(split(df, df$lyr_bot), function(x) {
    tukey.table.fx(x, paste0(unique(df$PMeco), " 2001 vs. 2019"), "inc", "year")
  })
})
NaNs producedNaNs producedNaNs produced
$ANpp
$ANpp$`10`
0-10 cm
ANpp 2001 vs. 2019 inc year
year.diff year.lwr year.upr year.p.adj Pairs
-112.068 -168.378 -55.758 0.013 2019-2001

$ANpp$`20`
10-20 cm
ANpp 2001 vs. 2019 inc year
year.diff year.lwr year.upr year.p.adj Pairs
-41.107 -126.069 43.856 0.173 2019-2001

$ANpp$`30`
20-30 cm
ANpp 2001 vs. 2019 inc year
year.diff year.lwr year.upr year.p.adj Pairs
26.321 -162.239 214.88 0.609 2019-2001


$ANrf
$ANrf$`10`
0-10 cm
ANrf 2001 vs. 2019 inc year
year.diff year.lwr year.upr year.p.adj Pairs
-53.528 -70.509 -36.547 0.005 2019-2001

$ANrf$`20`
10-20 cm
ANrf 2001 vs. 2019 inc year
year.diff year.lwr year.upr year.p.adj Pairs
-20.65 -71.163 29.863 0.221 2019-2001

$ANrf$`30`
20-30 cm
ANrf 2001 vs. 2019 inc year
year.diff year.lwr year.upr year.p.adj Pairs
20.616 -7.758 48.989 0.089 2019-2001


$ANwf
$ANwf$`10`
0-10 cm
ANwf 2001 vs. 2019 inc year
year.diff year.lwr year.upr year.p.adj Pairs
-25.061 -123.937 73.815 0.39 2019-2001

$ANwf$`20`
10-20 cm
ANwf 2001 vs. 2019 inc year
year.diff year.lwr year.upr year.p.adj Pairs
-18.73 -25.823 -11.636 0.007 2019-2001

$ANwf$`30`
20-30 cm
ANwf 2001 vs. 2019 inc year
year.diff year.lwr year.upr year.p.adj Pairs
-26.671 -63.212 9.87 0.088 2019-2001


$BSpp
$BSpp$`10`
0-10 cm
BSpp 2001 vs. 2019 inc year
year.diff year.lwr year.upr year.p.adj Pairs
-41.7 -75.535 -7.865 0.034 2019-2001

$BSpp$`20`
10-20 cm
BSpp 2001 vs. 2019 inc year
year.diff year.lwr year.upr year.p.adj Pairs
-20.628 -38.25 -3.006 0.037 2019-2001

$BSpp$`30`
20-30 cm
BSpp 2001 vs. 2019 inc year
year.diff year.lwr year.upr year.p.adj Pairs
9.436 -108.88 127.751 0.764 2019-2001


$BSrf
$BSrf$`10`
0-10 cm
BSrf 2001 vs. 2019 inc year
year.diff year.lwr year.upr year.p.adj Pairs
-69.149 -82.933 -55.365 0.002 2019-2001

$BSrf$`20`
10-20 cm
BSrf 2001 vs. 2019 inc year
year.diff year.lwr year.upr year.p.adj Pairs
-72.152 -162.05 17.746 0.075 2019-2001

$BSrf$`30`
20-30 cm
BSrf 2001 vs. 2019 inc year
year.diff year.lwr year.upr year.p.adj Pairs
-61.935 -70.107 -53.763 0 2019-2001


$BSwf
$BSwf$`10`
0-10 cm
BSwf 2001 vs. 2019 inc year
year.diff year.lwr year.upr year.p.adj Pairs
-67.026 -82.623 -51.43 0.002 2019-2001

$BSwf$`20`
10-20 cm
BSwf 2001 vs. 2019 inc year
year.diff year.lwr year.upr year.p.adj Pairs
-107.373 -168.048 -46.697 0.017 2019-2001

$BSwf$`30`
20-30 cm
BSwf 2001 vs. 2019 inc year
year.diff year.lwr year.upr year.p.adj Pairs
-139.763 -241.947 -37.579 0.028 2019-2001


$GRpp
$GRpp$`10`
0-10 cm
GRpp 2001 vs. 2019 inc year
year.diff year.lwr year.upr year.p.adj Pairs
-89.459 -114.521 -64.397 0.004 2019-2001

$GRpp$`20`
10-20 cm
GRpp 2001 vs. 2019 inc year
year.diff year.lwr year.upr year.p.adj Pairs
25.06 -77.741 127.86 0.405 2019-2001

$GRpp$`30`
20-30 cm
GRpp 2001 vs. 2019 inc year
year.diff year.lwr year.upr year.p.adj Pairs
49.63 -228.753 328.013 0.524 2019-2001


$GRrf
$GRrf$`10`
0-10 cm
GRrf 2001 vs. 2019 inc year
year.diff year.lwr year.upr year.p.adj Pairs
-13.237 -147.681 121.206 0.713 2019-2001

$GRrf$`20`
10-20 cm
GRrf 2001 vs. 2019 inc year
year.diff year.lwr year.upr year.p.adj Pairs
69.3 NaN NaN NaN 2019-2001

$GRrf$`30`
20-30 cm
GRrf 2001 vs. 2019 inc year
year.diff year.lwr year.upr year.p.adj Pairs
166.594 NaN NaN NaN 2019-2001


$GRwf
$GRwf$`10`
0-10 cm
GRwf 2001 vs. 2019 inc year
year.diff year.lwr year.upr year.p.adj Pairs
-55.927 -101.954 -9.899 0.035 2019-2001

$GRwf$`20`
10-20 cm
GRwf 2001 vs. 2019 inc year
year.diff year.lwr year.upr year.p.adj Pairs
-77.344 -162.104 7.416 0.059 2019-2001

$GRwf$`30`
20-30 cm
GRwf 2001 vs. 2019 inc year
year.diff year.lwr year.upr year.p.adj Pairs
0.089 -36.296 36.474 0.993 2019-2001
lapply(split(sra.01.19.inc.df, sra.01.19.inc.df$PM), function(df) {
  lapply(split(df, df$lyr_bot), function(x) {
    tukey.table.fx(x, paste0(unique(df$PM), " 2001 vs. 2019"), "inc", "year")
  })
})
$AN
$AN$`10`
0-10 cm
AN 2001 vs. 2019 inc year
year.diff year.lwr year.upr year.p.adj Pairs
-63.553 -94.114 -32.991 0.001 2019-2001

$AN$`20`
10-20 cm
AN 2001 vs. 2019 inc year
year.diff year.lwr year.upr year.p.adj Pairs
-26.829 -48.81 -4.847 0.022 2019-2001

$AN$`30`
20-30 cm
AN 2001 vs. 2019 inc year
year.diff year.lwr year.upr year.p.adj Pairs
6.755 -37.035 50.545 0.738 2019-2001


$BS
$BS$`10`
0-10 cm
BS 2001 vs. 2019 inc year
year.diff year.lwr year.upr year.p.adj Pairs
-59.292 -79.352 -39.232 0 2019-2001

$BS$`20`
10-20 cm
BS 2001 vs. 2019 inc year
year.diff year.lwr year.upr year.p.adj Pairs
-66.718 -102.636 -30.799 0.002 2019-2001

$BS$`30`
20-30 cm
BS 2001 vs. 2019 inc year
year.diff year.lwr year.upr year.p.adj Pairs
-64.087 -123.626 -4.549 0.037 2019-2001


$GR
$GR$`10`
0-10 cm
GR 2001 vs. 2019 inc year
year.diff year.lwr year.upr year.p.adj Pairs
-52.874 -112.814 7.065 0.078 2019-2001

$GR$`20`
10-20 cm
GR 2001 vs. 2019 inc year
year.diff year.lwr year.upr year.p.adj Pairs
-7.054 -105.253 91.146 0.873 2019-2001

$GR$`30`
20-30 cm
GR 2001 vs. 2019 inc year
year.diff year.lwr year.upr year.p.adj Pairs
47.18 -45.261 139.621 0.278 2019-2001
lapply(split(sra.01.19.inc.df, sra.01.19.inc.df$ECO), function(df) {
  lapply(split(df, df$lyr_bot), function(x) {
    tukey.table.fx(x, paste0(unique(df$ECO), " 2001 vs. 2019"), "inc", "year")
  })
})
$pp
$pp$`10`
0-10 cm
pp 2001 vs. 2019 inc year
year.diff year.lwr year.upr year.p.adj Pairs
-81.076 -110.49 -51.662 0 2019-2001

$pp$`20`
10-20 cm
pp 2001 vs. 2019 inc year
year.diff year.lwr year.upr year.p.adj Pairs
-12.225 -41.041 16.591 0.367 2019-2001

$pp$`30`
20-30 cm
pp 2001 vs. 2019 inc year
year.diff year.lwr year.upr year.p.adj Pairs
28.462 -20.711 77.636 0.226 2019-2001


$rf
$rf$`10`
0-10 cm
rf 2001 vs. 2019 inc year
year.diff year.lwr year.upr year.p.adj Pairs
-45.305 -84.505 -6.104 0.028 2019-2001

$rf$`20`
10-20 cm
rf 2001 vs. 2019 inc year
year.diff year.lwr year.upr year.p.adj Pairs
-23.261 -119.616 73.094 0.593 2019-2001

$rf$`30`
20-30 cm
rf 2001 vs. 2019 inc year
year.diff year.lwr year.upr year.p.adj Pairs
9.738 -101.496 120.971 0.847 2019-2001


$wf
$wf$`10`
0-10 cm
wf 2001 vs. 2019 inc year
year.diff year.lwr year.upr year.p.adj Pairs
-49.338 -79.02 -19.657 0.004 2019-2001

$wf$`20`
10-20 cm
wf 2001 vs. 2019 inc year
year.diff year.lwr year.upr year.p.adj Pairs
-67.816 -112.331 -23.3 0.007 2019-2001

$wf$`30`
20-30 cm
wf 2001 vs. 2019 inc year
year.diff year.lwr year.upr year.p.adj Pairs
-55.448 -108.861 -2.035 0.043 2019-2001
NANA
sra.01.19.min.reps <- left_join(
  merge(sra.01.19.bulk.df, sra.01.19.inc.df,
        by = c("PMeco", "PM", "ECO", "year", "lyr_bot"),
        suffixes = c("_blk", "_inc")),
  ras18.sp.df[ , c("Al_ox", "Al_py", "Fe_dc", "Fe_ox", "PM", "ECO", "lyr_bot")],
  by = c("PM", "ECO", "lyr_bot")) %>%
  mutate(Year = as.numeric(as.character(year)))

summary(lm(d14c_blk ~ Al_ox + lyr_bot + year, sra.01.19.min.reps))

Call:
lm(formula = d14c_blk ~ Al_ox + lyr_bot + year, data = sra.01.19.min.reps)

Residuals:
    Min      1Q  Median      3Q     Max 
-89.532 -27.114  -0.197  26.055 115.938 

Coefficients:
            Estimate Std. Error t value     Pr(>|t|)    
(Intercept) 108.5757     6.0801  17.858      < 2e-16 ***
Al_ox        -1.9945     0.1687 -11.822      < 2e-16 ***
lyr_bot      -3.0592     0.2487 -12.300      < 2e-16 ***
year2019    -22.4127     4.0521  -5.531 0.0000000671 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 36.11 on 314 degrees of freedom
Multiple R-squared:  0.527, Adjusted R-squared:  0.5225 
F-statistic: 116.6 on 3 and 314 DF,  p-value: < 2.2e-16
sra.01.19.min.reps %>%
  mutate(eco = ifelse(ECO == "rf", "cold", ifelse(ECO == "wf", "cool", "warm"))) %>%
  mutate(ecoYear = paste0(eco, " (", year, ")")) %>%
  # filter(pmEcoDepth != "granitecold30" & pmEcoDepth != "granitecold20") %>%
  ggplot(., aes(Al_ox, d14c_blk)) +
  geom_point(aes(color = PM, shape = ecoYear), size = 3) +
  scale_color_manual(name = "Parent material",
                     values = c("AN" = andesite,
                                "BS" = basalt,
                                "GR" = granite),
                     labels = c("AN" = "andesite",
                               "BS" = "basalt",
                               "GR" = "granite")) + 
  scale_shape_manual(name = "Climate (year)",
                     values = c("warm (2001)" = 15, 
                                "cool (2001)" = 16, 
                                "cold (2001)" = 17,
                                "warm (2019)" = 0, 
                                "cool (2019)" = 1, 
                                "cold (2019)" = 2)) +
  facet_wrap(vars(lyr_bot)) +
  ylab(expression('Bulk '*Delta*''^14*'C (‰)')) +
  xlab(expression('Oxalate extractable Al (g kg'^-1*')')) +
  theme_bw() +
  theme(panel.grid.minor = element_blank())

# color palettes for ECO & PM
warm <- "#BF812D"
cool <- "#80CDC1"
cold <- "#01665E"
granite <- "#9daba9"
andesite <- "#382dbf"
basalt <- "#bf382d"

# plot fx
boxplot.fx <- function(df, var, year, type, topsoil = FALSE, subsoil = FALSE) {
  atm <- ifelse(year == "2001", atm.d14.2001, atm.d14.2019)
  if (type == "inc") {
    df <- df[df$d14c > -200, ]
    ylim <- c(-65, 165)
  } else {
    if (topsoil) {
      df <- df[df$lyr_bot < 31, ]
      ylim <- c(-120, 165)
      }
    if (subsoil) {
      df <- df[df$lyr_bot > 31, ]
      ylim <- c(-270, 65)
    }
  }
  if (var == "PM") {
    df %>%
      mutate(pm = factor(ifelse(PM == "GR", "granite",
                                ifelse(PM == "AN", "andesite", "basalt")),
                         levels = c("granite", "andesite", "basalt"))) %>%
      group_by(pm, lyr_bot) %>%
      ggplot(., aes(pm, d14c)) +
      geom_hline(yintercept = atm, linetype = "dotted", alpha = 0.3) +
      geom_hline(yintercept = 0) +
      geom_boxplot(aes(color = pm), lwd = 1) +
      scale_color_manual(values = c("andesite" = andesite,
                                    "basalt" = basalt,
                                    "granite" = granite),
                         guide = "none") +
      scale_y_continuous(limits = ylim) +
      facet_grid(cols = vars(lyr_bot)) +
      ylab(expression(Delta*''^14*'C (‰)')) +
      ggtitle(paste(year, type)) +
      theme_bw() +
      theme(panel.grid = element_blank(),
            text = element_text(size = 14))
  } else {
    df %>%
      mutate(eco = factor(ifelse(ECO == "pp", "warm",
                                 ifelse(ECO == "wf", "cool", "cold")),
                          levels = c("warm", "cool", "cold"))) %>%
      group_by(eco, lyr_bot) %>%
      ggplot(., aes(eco, d14c)) +
      geom_hline(yintercept = atm, linetype = "dotted", alpha = 0.3) +
      geom_hline(yintercept = 0) +
      geom_boxplot(aes(color = eco), lwd = 1) +
      scale_color_manual(values = c("warm" = warm,
                                    "cool" = cool,
                                    "cold" = cold),
                         guide = "none") +
      scale_y_continuous(limits = ylim) +
      facet_grid(cols = vars(lyr_bot)) +
      ylab(expression(Delta*''^14*'C (‰)')) +
      ggtitle(paste(year, type)) +
      theme_bw() +
      theme(panel.grid = element_blank(),
            text = element_text(size = 14))
  }
}

# bulk
boxplot.fx(sra.2001.bulk.df, "PM", "2001", "bulk", topsoil = TRUE)

boxplot.fx(sra.2019.bulk.df, "PM", "2019", "bulk", topsoil = TRUE)

boxplot.fx(sra.2001.bulk.df, "ECO", "2001", "bulk", topsoil = TRUE)

boxplot.fx(sra.2019.bulk.df, "ECO", "2019", "bulk", topsoil = TRUE)

boxplot.fx(sra.2019.bulk.df, "ECO", "2019", "bulk", subsoil = TRUE)

# inc
boxplot.fx(sra.2001.inc.df2, "PM", "2001", "inc")

boxplot.fx(sra.2019.inc.df2, "PM", "2019", "inc")

boxplot.fx(sra.2001.inc.df2, "ECO", "2001", "inc")

boxplot.fx(sra.2019.inc.df2, "ECO", "2019", "inc")

# data, unsummarized
sra.ts.all.raw <- rbind(
  sra.2001.bulk.df[ , names(sra.2001.bulk.df) %in% names(sra.2001.inc.df2)],
  sra.2019.bulk.df[ , names(sra.2019.bulk.df) %in% names(sra.2001.inc.df2)],
  sra.2001.inc.df2,
  sra.2019.inc.df2[ , names(sra.2019.inc.df2) %in% names(sra.2001.inc.df2)]) %>%
  mutate(eco = factor(ifelse(ECO == "pp", "warm",
                             ifelse(ECO == "wf", "cool", "cold")),
                      levels = c("warm", "cool", "cold")),
         pm = factor(ifelse(PM == "GR", "granite",
                                ifelse(PM == "AN", "andesite", "basalt")),
                         levels = c("granite", "andesite", "basalt")),
         Type = c(rep("bulk", length = nrow(sra.2001.bulk.df)),
                  rep("bulk", length = nrow(sra.2019.bulk.df)),
                  rep("inc", length = nrow(sra.2001.inc.df2)),
                  rep("inc", length = nrow(sra.2019.inc.df2))),
         year = c(rep(2001, length = nrow(sra.2001.bulk.df)),
                  rep(2019, length = nrow(sra.2019.bulk.df)),
                  rep(2001, length = nrow(sra.2001.inc.df2)),
                  rep(2019, length = nrow(sra.2019.inc.df2))))

# plot fx
ts.groupPlot.fx <- function(df, x, y) {
  quo_x <- sym(x)
  quo_y <- sym(y)
  if (x == "pm") {
    var.name <- "Parent material"
    var.values <- c("andesite" = andesite,
                    "basalt" = basalt,
                    "granite" = granite) 
  } else {
    var.name <- "Climate"
    var.values <-  c("warm" = warm,
                     "cool" = cool,
                     "cold" = cold)
  }
  plot.df <- df %>%
    filter(d14c > -200) %>%
    filter(lyr_bot < 31) %>%
    group_by(!! quo_x, lyr_bot, Type, year) %>%
    summarize(across(d14c, list(mean = mean, sd = sd)))
  if (y == "dd14c") {
    plot.df <- plot.df %>%
      mutate(atm = ifelse(year == 2001, atm.d14.2001, atm.d14.2019),
             dd14c = d14c_mean - atm,
             u = d14c_mean + d14c_sd - atm,
             l = d14c_mean - d14c_sd - atm)
    atm.df <- atm.14c
    atm.df$d14c <- 0
    ylab <- expression(Delta*Delta*''^14*'C (‰)') 
    } else {
      plot.df <- plot.df %>%
        mutate(u = d14c_mean + d14c_sd,
               l = d14c_mean - d14c_sd)
      atm.df <- atm.14c
      ylab <- expression(Delta*''^14*'C (‰)') 
    }
    ggplot(plot.df, aes(year, !! quo_y)) +
    geom_path(data = atm.df, aes(year, d14c)) +
    geom_path(aes(color = !! quo_x, linetype = Type), alpha = .5, lwd = 1) +
    geom_point(aes(color = !! quo_x), 
               size = 3, position = position_dodge(width = 1)) +
    geom_errorbar(
      aes(ymin = l,
          ymax = u,
          color = !! quo_x,
          alpha = Type),
      width = 1,
      position = position_dodge(width = 1)) +
    scale_color_manual(name = var.name,
                       values = var.values) +
    scale_fill_manual(name = "±SD",
                      values = var.values) +
    scale_alpha_manual(values = c("bulk" = 1,
                                  "inc" = .5)) +
    facet_grid(cols = vars(lyr_bot)) +
    ylab(ylab) +
    xlab("Year") +
    theme_bw() +
    theme(panel.grid = element_blank())
}
# plot
ts.groupPlot.fx(sra.ts.all.raw, "pm", "dd14c")

ts.groupPlot.fx(sra.ts.all.raw, "eco", "dd14c")

ts.groupPlot.fx(sra.ts.all.raw, "pm", "d14c_mean")

ts.groupPlot.fx(sra.ts.all.raw, "eco", "d14c_mean")

Initial modeling

The goal of this modeling exercise is to see how parent material and climate/ecosystem affect estimates of soil carbon ages and transit times. Bulk soil 14C observations from 2001, 2009, and 2019 will be used to constrain the carbon models, as well as observations of 14C-CO2 from laboratory soil incubations of soils collected in 2001 and 2019. Previous work has indicated that the carbon stocks at these sites is likely at equilibrium, so we will apply the steady-state assumption to the modeling.

Two-pool models

One pool models have been shown repeatedly to be inadequate for describing soil carbon dynamics. However, as simple models are easier to constrain, we will start with a two-pool parallel and two-series models, as these are the simplest model system beyond the single pool approach.

The two-pool parallel model requires the following parameters: * decomposition constants for each pool (k1, k2) * input partitioning coefficient (\(\gamma\)) * steady-state carbon stocks (C) * inputs (I) * initial values of 14C 1 The two-pool series model requires the following parameters: * decomposition constants for each pool (k1, k2) * transfer coefficient (\(\alpha\)) * steady-state carbon stocks (C) * inputs (I) * initial values of 14C

Decomposition rates (k) are related to the amount of 14C in a pre-bomb system (fraction modern, F) at steady-state by the following equations (cf. Schuur, Druffle, and Trumbore, 2016): >Eq. 1

\[F = \frac{k}{k + \lambda}\] >Eq. 2

\[k = \frac{\lambda \cdot F}{1 - F}\] >where \(\lambda\) is the radioactive decay constant (1/8267).

As the decomposition rates will vary, the initial 14C content can be determined dynamically with equation 1.

Carbon stocks are known, while inputs will be estimated and are related to the steady-state conditions by the following equation: >Eq. 3

\[I = (k_{1} \cdot C_{1}) + (k_{2} \cdot C_{2})\] >where C1 and C2 are the carbon stocks of the two model pools.

Both stocks and inputs can be scaled to the known value of the total carbon pool once the steady-state parameters (k1, k2, and \(\gamma\) or \(\alpha\)) have been determined. Pool sizes are a function of the inputs and input partitioning coefficient at steady-state.

A Monte-Carlo Markov chain approach will be used for parameter estimation in combination with an initial optimization algorithm to determine the best set of initial parameters.

Workflow

Initial model fitting was performed for both model structures using generous parameter ranges [0, 1] for all three parameters (k1, k2, \(\gamma\) or \(\alpha\)). The initial parameter set was found by fitting the models by eye, followed by optimization with the function “modFit” (R package FME), using the Nelder-Mead algorithm. The best set of parameters found by modFit was then used as the input to a Monte Carlo Markov Chain (MCMC), using the function “modMCMC” (R package FME). The number of iterations for the MCMC optimization was set at 5000 intially, with delayed rejection employed to increase efficiency.

The sum of the mean squared error for the best parameter set was slightly lower for the parallel structure than for the series structure. Additionally, the overall mean error of the residuals was also lower for the parallel structure, moderately so for the bulk C observations but substantially so for the respiration observations (in andesite and granite soils in particular).

However, these initial fits yielded unrealistic parameter estimates for multiple sites, particularly at the lower depths. Additionally, the modFit output showed very high correlation between the parameters for both model structures (slightly higher for the two-pool series model).

# k from fraction modern
k <- function (Fm) {
  (Fm * lambda)/(1 - Fm)
}

# d14C from fraction modern 
fm_14c <- function (fm, date) {
  (fm * exp(lambda * (1950 - date)) - 1) * 1000
}

# pre-bomb fraction modern from k (steady-state assumed)
fm <- function (k){
  k/(k + lambda)
}
# index of years for which bulk/resp 14C are known
year.ix <- c(which(Datm$Date == 2001.5),
             which(Datm$Date == 2009.5),
             which(Datm$Date == 2019.5))

# function for saving constraint data in a dataframe for plotting in ggplot'
con.df.fx <- function(PMeco_depth) {
  bulk.df <- obs.bulk.14c[[PMeco_depth]]
  resp.df <- obs.resp.14c[[PMeco_depth]]
  return(
    con.df <- data.frame(pool = c(rep("bulk C", nrow(bulk.df)), rep("respiration", nrow(resp.df))),
                         d14c = c(bulk.df$bulkC, resp.df$resp),
                         Year = c(bulk.df$time, resp.df$time)))
}

# plot function
C14.2p.plot.fx <- function(plot.df, con.df, mod, PMeco_depth) {
  plot.df %>%
  filter(pool == "bulk C" | pool == "respiration" | pool == "atm") %>%
  ggplot(., aes(years, d14C, color = pool)) +
  geom_path() +
  geom_point(data = con.df, aes(Year, d14c, color = pool), size = 3) +
  scale_color_manual(
    name = "Pool",
    values = c("atm" = 8,
               "bulk C" = "black",
               "fast" = "#D81B60",
               "slow" = "#1E88E5",
               "respiration" = "#FFC107")) +
  scale_x_continuous(limits = c(1950, 2022)) +
  ggtitle(paste(PMeco_depth, mod)) +
  xlab("Year") +
  ylab(expression(''*Delta*''^14*'C (‰)')) +
  theme_bw() +
  theme(panel.grid = element_blank())
}
C14.1p.plot.fx <- function(plot.df, con.df, mod, PMeco_depth) {
  ggplot(plot.df, aes(years, d14C, color = pool)) +
  geom_path() +
  geom_point(data = con.df, aes(Year, d14c, color = pool), size = 3) +
  scale_color_manual(
    name = "Pool",
    values = c("atm" = 8,
               "bulk C" = "black",
               "respiration" = "#FFC107")) +
  scale_x_continuous(limits = c(1950, 2022)) +
  ggtitle(paste(PMeco_depth, " 1p bulk + 1p resp")) +
  xlab("Year") +
  ylab(expression(''*Delta*''^14*'C (‰)')) +
  theme_bw() +
  theme(panel.grid = element_blank())
}

# set up model function for optimization
# NOTE: par[3] for 2ps model changed to proportion transferred (no longer = a21)
# therefore, a21 = par[3] * par[1]
modFun_2p <- function(pars, In, lag = 0, pass = TRUE, out = "modFit", mod) {
 
  # intial 14C
  F0_Delta14C <- unlist(lapply(pars[1:2], function(x) Delta14C_from_AbsoluteFractionModern(fm(x))))
  
  # model matrix
  A <- -diag(pars[1:2])
  if (mod == "2ps") {
    a21 <- pars[3] * pars[1]
    A[2, 1] <- a21
  }
    
  # steady-state C stocks
  if (mod == "2pp") {
    ss.cstock <- (-1 * solve(A) %*% c(In * pars[3], In * (1 - pars[3])))
  } else {
    ss.cstock <- (-1 * solve(A) %*% c(In, 0))
  }
  
  # time index
  ix.t <- c((lag + 1):nrow(Datm))
  
  # model
  if (mod == "2pp") {
    mod <- TwopParallelModel14(t = Datm$Date[ix.t],
                               ks = pars[1:2],
                               C0 = c(ss.cstock[1], ss.cstock[2]),
                               F0_Delta14C = F0_Delta14C,
                               In = In,
                               gam = pars[3],
                               inputFc = Datm,
                               lag = lag,
                               pass = pass)
  } else {
    mod <- TwopSeriesModel14(t = Datm$Date[ix.t],
                             ks = pars[1:2],
                             C0 = c(ss.cstock[1], ss.cstock[2]),
                             F0_Delta14C = F0_Delta14C,
                             In = In,
                             a21 = a21,
                             inputFc = Datm,
                             lag = lag,
                             pass = pass)
  }
  
  # get mod values
  C14m <- getF14C(mod)
  C14p <- getF14(mod)
  C14r <- getF14R(mod)
  Ctot <- getC(mod)
  
  if(out == "modFit") {
    # dataframe for modFit fx
    return(data.frame(
      time = Datm$Date[ix.t],
      bulkC = C14m, 
      resp = C14r,
      cStock = rowSums(Ctot)))
  } else {
    # data frame for plotting
    return(data.frame(
      years = rep(Datm$Date[ix.t], 5),
      d14C = c(C14p[,1], 
               C14p[,2], 
               C14m,
               C14r,
               Datm$NHc14[ix.t]),
      pool = rep(c("fast", "slow", "bulk C", "respiration", "atm"), each = nrow(C14p))))
  }
}

# 1p modFun
modFun_1p <- function(pars, In, lag = 0, out = "modFit", mod, pass = TRUE) {
 
  # intial 14C
  F0_Delta14C <- Delta14C_from_AbsoluteFractionModern(fm(pars))
  
  # steady-state C stocks
  ss.cstock <- In/pars
  
  # time index
  ix.t <- c((lag + 1):nrow(Datm))
  
  # model
  mod <- suppressWarnings(
    # warnings suppressed due to the "Fc" warning
    OnepModel14(t = Datm$Date[ix.t],
                     k = pars,
                     C0 = ss.cstock,
                     F0_Delta14C = F0_Delta14C,
                     In = In,
                     inputFc = Datm,
                     lag = lag,
                     pass = pass)
  )
  
  # get mod values
  C14m <- getF14C(mod)
  Ctot <- getC(mod)
  
  if(out == "modFit") {
    # dataframe for modFit fx
    return(data.frame(
      time = Datm$Date[ix.t],
      bulkC = C14m,
      cStock = Ctot))
  } else {
    # data frame for plotting
    return(data.frame(
      years = rep(Datm$Date[ix.t], 1),
      d14C = c(C14m,
               Datm$NHc14[ix.t]),
      pool = rep(c("bulk C", "atm"), each = length(C14m))))
  }
}

# function for trial and error approach to finding initial parameter set
par.fx <- function(pars, In, lag = 0, out = "plot.df", verbose = TRUE, mod, pass = FALSE) {
  
  # model matrix
  A <- -diag(pars[1:2])
  if (mod == "2ps") {
    a21 <- pars[3] * pars[1]
    A[2, 1] <- a21
    # steady-state stocks
    ss.cstock <- round((-1 * solve(A) %*% c(In, 0)), 1)
  } else if (mod == "2pp") {
    # steady-state stocks
    ss.cstock <- round((-1 * solve(A) %*% c(In * pars[3], In * (1 - pars[3]))), 1)
  } else {
    ss.cstock <- In/pars
  }
  
  cstock.sum <- ifelse(length(ss.cstock) == 1, ss.cstock, colSums(ss.cstock))
  
  # print site and steady-state stocks
  if (verbose) {
    cat(paste0(PMeco_depth, "\n"))
    if (mod == "2ps" | mod == "2pp") {
      cat(paste0(ss.cstock[1], " (fast pool)\n", ss.cstock[2], " (slow pool)\n"))
      cat(paste0("slow pool: ", round(ss.cstock[2] / cstock.sum * 100, 0), "%\n")) 
    }
    cat(round(cstock.sum, 1), " (modeled stocks)\n")
    cat(round(csoc.19.0_30[[PMeco_depth]][ , "lyr_soc"], 1), " (measured stocks)\n") 
  }
  if (mod == "1p") {
    return(modFun_1p(pars = pars, In = In, lag = lag, out = out, mod = "1p", pass = pass))
  }
  if (mod == "2pp") {
   return(modFun_2p(pars = pars, In = In, lag = lag, out = out, mod = "2pp", pass = pass)) 
  } else if (mod == "2ps") {
    return(modFun_2p(pars = pars, In = In, lag = lag, out = out, mod = "2ps", pass = pass)) 
  }
}
## adjust inputs to match stocks
# function for calculating steady-state SOC stocks
soc.fx <- function(modStr, pars, In, out = "pools") {
  if (modStr == "2pp") {
    cmat <- -1 * solve(-diag(pars[1:2])) %*% c(In * pars[3], In * (1 - pars[3]))
  } else {
    A <- -diag(pars[1:2])
    A[2, 1] <- pars[3] # note that a21 defined as pct transfer * k1
    cmat <- -1 * solve(A) %*% c(In, 0) # In is total input into the system
  }
  if (out == "pools") {
    return(cmat)
  } else {
    return(colSums(cmat))
  }
}

in.fit.fx <- function(modStr, pars, initialIn, SOC) {
  # sequence of possible input values
  if  (SOC < soc.fx(modStr, pars, initialIn, out = "sum")) {
    ins <- seq(.01, 
               initialIn, 
               .01)
    } else {
      ins <- seq(initialIn, 
                 SOC, 
                 .01)
    }
  # modeled stocks
  soc_mod <- lapply(seq_along(ins), function(j) {
    soc.fx(modStr, pars, ins[j], out = "sum")
  })
  ix <- which.min(abs(unlist(soc_mod) - SOC))
  return(ins[ix])
}

# load initial parameter set
load("../data/derived/modFit_pars/pars.i.2pp_2021-03-30.Rdata")
load("../data/derived/modFit_pars/pars.i.2ps_2020-11-16.Rdata")

## inputs for initial par set and measured stocks
# 2pp
in.meas.2pp <- lapply(seq_along(pars.i.2pp[ix.10]), function(i) {
  PMeco_depth <- names(pars.i.2pp[ix.10])[i]
  SOC <- csoc.19.0_30[[PMeco_depth]][ ,"lyr_soc"]
  return(in.fit.fx("2pp", pars.i.2pp[ix.10][[i]], in.i[ix.10][[i]], SOC))
})
names(in.meas.2pp) <- names(pars.i.2pp[ix.10])
# 2ps
in.meas.2ps <- lapply(seq_along(pars.i.2ps[ix.10]), function(i) {
  PMeco_depth <- names(pars.i.2ps[ix.10])[i]
  SOC <- csoc.19.0_30[[PMeco_depth]][ ,"lyr_soc"]
  return(in.fit.fx("2pp", pars.i.2ps[ix.10][[i]], in.i[ix.10][[i]], SOC))
})
names(in.meas.2ps) <- names(pars.i.2ps[ix.10])

# Flux estimated from Goulden et al. 2012; Tang et al. 2005; Wang et al. 2000; Gaudinski 2000
# fluxes by elevation from GPP reported in Goulden et al. Fig. 5 and approximated
# Rh percentage from Tang et al. 2005 = 0.44 (ann. mean Blodgett); cf. 0.48 Harvard Forest
# A horizon est. 0.55 from Gaudinski
# assuming A = 0-30, assume 0-10 = 50%, 10-20 = 30%, 20-30 = 20% of total A production 
hznA.Rh.kgm2 <- 0.44 * 0.55 * 10^-3
gpp.ls <- c(1800, 1600, 1400)
in.frc.ls <- c(0.5, 0.3, 0.2)

# fx for calculating inputs
in.flx.fx <- function(PMeco_depth) {
  gpp <- ifelse(grepl("pp", PMeco_depth), gpp.ls[1], ifelse(grepl("wf", PMeco_depth), gpp.ls[2], gpp.ls[3]))
  in.frc <- ifelse(grepl("0-10", PMeco_depth), in.frc.ls[1], ifelse(grepl("10-20", PMeco_depth), in.frc.ls[2], in.frc.ls[3]))
  return(gpp * in.frc * hznA.Rh.kgm2)
}

# input list
in.est <- lapply(seq_along(pars.i.2pp), function(i) {
  PMeco_depth <- names(pars.i.2pp)[i]
  return(in.flx.fx(PMeco_depth))
})
names(in.est) <- names(pars.i.2pp)

Parameter optimization

Optimizing the parameter set requires imposing costs and optionally constraining the allowable range of values for each parameter. Given that we only have data for three time points, this is a relatively sparse data set for constraining these models. Accordingly, the optimization procedure will benefit from a priori constraints of the allowable parameter ranges. For example, since we assume that the system cannot be adequately modeled as a single homogenous reservoir, we will ensure that the optimization procedure cannot collapse the two-pool system into a single pool. This can be mitigated in the two-pool parallel optimization by constraining \(\gamma\) (i.e. the percentage of the inputs entering the fast pool) to a range of 50% to 95%. Similarly, for the two-pool series model structure we can constrain the range of the transfer coefficient to be between 0.0 and 0.1, ensuring that some carbon remains in the fast cycling pool.

Additionally, to enforce a relatively fast cycling pool and relatively slower cycling pool, we will loosely constrain the intrinsic decomposition rates as well (both model structures):

k1: [0.02, 1.00] (50 to 1 year) k2: [0.0001, 0.02] (10,000 to 50 years)

Finally, the models will be run to enforce steady-state, i.e. with unvarying carbon stocks. The amount of carbon observed in the system will be used in the cost function in addition to the radiocarbon observations made in 2001, 2009, and 2019. The inputs will be estimated from net ecosystem exchange (NEE) data measured at nearby eddy covariance sites: Blodgett experimental forest (AmeriFlux), Lower Teakettle (NEON), and Soaproot Saddle (NEON). Alternatively, using correlations between fluxes measured from these eddy covariance towers and GPP estimated from satellite retrievals of SIF, estimates can be made for inputs at the pixels corresponding to each site location.

# Note: this only runs if eval flag switched to TRUE
## Optimize model pars
# Cost function (evaluates error as model vs. obsv, per FME req)
# note that we have to set "pass" to TRUE so SoilR model doesn't fail (neg. resp)
mod.fits.fx <- function(mod, pars, In, sub, lag = 0, upper, lower, cost) {
  
  # start loop
  lapply(seq_along(pars[sub]), function(i) {
    
    # start timer and print PMeco_depth
    start <- Sys.time()
    cat(paste0(names(pars)[sub][i], " parameter fitting\n"))
  
    # define pars
    pars <- pars[sub][[i]]
    if (mod == "2pp") {
      names(pars) <- c("k1", "k2", "gam")
    } else {
      names(pars) <- c("k1", "k2", "tc")
    }
    
    # Set input
    In <- In[sub][[i]]
    
    # define cost function
    if (cost == "14C + cStock") {
      mod.Cost <- function(pars) {
        modelOutput <- modFun_2p(pars, In, mod = mod, lag = lag)
        cost1 <- modCost(model = modelOutput, obs = obs.bulk.14c[sub][[i]], scaleVar = TRUE)
        cost2 <- modCost(model = modelOutput, obs = obs.resp.14c[sub][[i]], scaleVar = TRUE, cost = cost1) 
        return(modCost(model = modelOutput, obs = obs.cStock[sub][[i]], cost = cost2))
      }
    } else if (cost == "14C + stock/flx") {
      mod.Cost <- function(pars) {
        modelOutput <- modFun_2p(pars, In, mod = mod, lag = lag)
        cost1 <- modCost(model = modelOutput, obs = obs.bulk.14c[sub][[i]], scaleVar = TRUE)
        cost2 <- modCost(model = modelOutput, obs = obs.resp.14c[sub][[i]], scaleVar = TRUE, cost = cost1) 
        return(modCost(model = modelOutput, obs = obs.flx.stock[[i]], cost = cost2))
      }
    } else if (cost == "14C") {
      mod.Cost <- function(pars) {
        modelOutput <- modFun_2p(pars, In, mod = mod, lag = lag)
        cost1 <- modCost(model = modelOutput, obs = obs.bulk.14c[sub][[i]], scaleVar = TRUE)
        return(modCost(model = modelOutput, obs = obs.resp.14c[sub][[i]], scaleVar = TRUE, cost = cost1))
      } 
    } else if (cost == "14C bulk + cStock") {
      mod.Cost <- function(pars) {
        modelOutput <- modFun_2p(pars, In, mod = mod, lag = lag)
        cost1 <- modCost(model = modelOutput, obs = obs.bulk.14c[sub][[i]], scaleVar = TRUE)
        return(modCost(model = modelOutput, obs = obs.cStock[sub][[i]], cost = cost1))
      }
    } else if (cost == "14C bulk only") {
      mod.Cost <- function(pars) {
        modelOutput <- modFun_2p(pars, In, mod = mod, lag = lag)
        return(modCost(model = modelOutput, obs = obs.bulk.14c[sub][[i]], scaleVar = TRUE))
      }
    }
    
    # fit pars
    fit <- tryCatch(
      modFit(f = mod.Cost,
             p = pars,
             method = 'Nelder-Mead',
             upper = upper, 
             lower = lower),
      error = function (e) {cat("ERROR :", conditionMessage(e), "\n")})
    
    Sfun <- sensFun(mod.Cost, fit$par)
    
    # End timer and print elapsed time
    end <- Sys.time()
    cat(paste0("time: ", end - start, "\n"))
    
    # Return fitted parameters and sensitivity
    return(list(modfit = fit, sens = Sfun))
  }) 
}

## 2pp
# par range [0, 1] for all pars
mod.sens.fits.2pp <- mod.fits.fx(mod = "2pp",
                                 pars = pars.i.2pp,
                                 In = in.i,
                                 sub = ix.10,
                                 upper = c(1, 1, 1),
                                 lower = c(0, 0, 0),
                                 cost = "14C")
names(mod.sens.fits.2pp) <- names(pars.i.2pp)[ix.10]
save(mod.sens.fits.2pp, file = paste0("../data/derived/modFit_pars/", "mod.fits.2pp", "_", Sys.Date(), ".Rdata"))
mod.fits.2pp <- lapply(mod.sens.fits.2pp, function(x) x[[1]])
# constrain gamma to [0.5, 0.95]
mod.sens.fits.2pp.p3.5.95 <- mod.fits.fx(mod = "2pp",
                                    pars = pars.i.2pp,
                                    sub = ix.10,
                                    In = in.i,
                                    upper = c(1, 1, 0.951),
                                    lower = c(0, 0, 0.5))
names(mod.sens.fits.2pp.p3.5.95) <- names(pars.i.2pp)[ix.10]
save(mod.sens.fits.2pp.p3.5.95, file = paste0("../data/derived/modFit_pars/", "mod.fits.2pp.p3.5.95", "_", Sys.Date(), ".Rdata"))
mod.fits.2pp.p3.5.95 <- lapply(mod.sens.fits.2pp.p3.5.95, function(x) x[[1]])

# 2pp3 (par range constraints, inputs fit to meas stocks)
mod.sens.fits.2pp3 <- mod.fits.fx(mod = "2pp",
                                  pars = pars.i.2pp,
                                  sub = ix.10,
                                  In = in.meas.2pp,
                                  upper = c(1, .02, .951),
                                  lower = c(.04, .0001, .5),
                                  cost = "14C only")
names(mod.sens.fits.2pp3) <- names(pars.i.2pp)[ix.10]
save(mod.sens.fits.2pp3, file = paste0("../data/derived/modFit_pars/", "mod.fits.2pp3", "_", Sys.Date(), ".Rdata"))
mod.fits.2pp3 <- lapply(mod.sens.fits.2pp3, function(x) x[[1]])
# 2pp3s (par range constraints, inputs fit to meas stocks, + stock constraint)
mod.sens.fits.2pp3s <- mod.fits.fx(mod = "2pp",
                                   pars = pars.i.2pp,
                                   sub = ix.10,
                                   In = in.meas.2pp,
                                   upper = c(1, .02, .951),
                                   lower = c(.04, .0001, .5),
                                   cost = "cStock")
names(mod.sens.fits.2pp3s) <- names(pars.i.2pp)[ix.10]
save(mod.sens.fits.2pp3s, file = paste0("../data/derived/modFit_pars/", "mod.fits.2pp3s", "_", Sys.Date(), ".Rdata"))
mod.fits.2pp3s <- lapply(mod.sens.fits.2pp3s, function(x) x[[1]])

## 2ps
# par range [0, 1] for all pars
mod.sens.fits.2ps <- mod.fits.fx(mod = "2ps",
                                 pars = pars.i.2ps, 
                                 sub = ix.10,
                                 In = in.i,
                                 upper = c(1, 1, 1),
                                 lower = c(0, 0, 0),
                                 cost = "14C")
names(mod.sens.fits.2ps) <- names(pars.i.2ps)[ix.10]
save(mod.sens.fits.2ps, file = paste0("../data/derived/modFit_pars/", "mod.fits.2ps", "_", Sys.Date(), ".Rdata"))
mod.fits.2ps <- lapply(mod.sens.fits.2ps, function(x) x[[1]])

# par range [0, 1] for all pars, stocks + 14C, w/ estimated inputs
# 10
mod.sens.fits.2ps5.10 <- mod.fits.fx(mod = "2ps",
                                     pars = pars.i.2ps, 
                                     sub = ix.10,
                                     In = in.est,
                                     upper = c(1, 1, 1),
                                     lower = c(0, 0, 0),
                                     cost = "14C + cStock")
names(mod.sens.fits.2ps5.10) <- names(pars.i.2ps)[ix.10]
save(mod.sens.fits.2ps5.10, file = paste0("../data/derived/modFit_pars/", "mod.sens.fits.2ps5.10", "_", Sys.Date(), ".Rdata"))
mod.fits.2ps5.10 <- lapply(mod.sens.fits.2ps5.10, function(x) x[[1]])
# 20
mod.sens.fits.2ps5.20 <- mod.fits.fx(mod = "2ps",
                                     pars = pars.i.2ps, 
                                     sub = ix.20,
                                     In = in.est,
                                     upper = c(1, 1, 1),
                                     lower = c(0, 0, 0),
                                     cost = "14C + cStock")
names(mod.sens.fits.2ps5.20) <- names(pars.i.2ps)[ix.20]
save(mod.sens.fits.2ps5.20, file = paste0("../data/derived/modFit_pars/", "mod.sens.fits.2ps5.20", "_", Sys.Date(), ".Rdata"))
mod.fits.2ps5.20 <- lapply(mod.sens.fits.2ps5.20, function(x) x[[1]])

# 20-30
mod.sens.fits.2ps.30 <- mod.fits.fx(mod = "2ps",
                                    pars = pars.i.2ps, 
                                    sub = ix.30,
                                    In = in.i,
                                    upper = c(1, 1, 1),
                                    lower = c(0, 0, 0),
                                    cost = "14C")
names(mod.sens.fits.2ps.30) <- names(pars.i.2ps)[ix.30]
save(mod.sens.fits.2ps.30, file = paste0("../data/derived/modFit_pars/", "mod.fits.2ps.30", "_", Sys.Date(), ".Rdata"))
mod.fits.2ps.30 <- lapply(mod.sens.fits.2ps.30, function(x) x[[1]])

# 2ps3 (par range constraints, inputs fit to meas stocks)
mod.sens.fits.2ps3 <- mod.fits.fx(mod = "2ps",
                                  pars = pars.i.2ps,
                                  sub = ix.10,
                                  In = in.meas.2ps,
                                  upper = c(1, 1, .15),
                                  lower = c(0, 0, .0004),
                                  cost = "14C only")
names(mod.sens.fits.2ps3) <- names(pars.i.2ps)[ix.10]
save(mod.sens.fits.2ps3, file = paste0("../data/derived/modFit_pars/", "mod.fits.2ps3", "_", Sys.Date(), ".Rdata"))
mod.fits.2ps3 <- lapply(mod.sens.fits.2ps3, function(x) x[[1]])
# 2ps3 (par range constraints, inputs fit to meas stocks, + stock constraint)
mod.sens.fits.2ps3s <- mod.fits.fx(mod = "2ps",
                                   pars = pars.i.2ps,
                                   sub = ix.10,
                                   In = in.meas.2ps,
                                   upper = c(1, .02, .1),
                                   lower = c(.04, .0001, 0),
                                   cost = "cStock")
names(mod.sens.fits.2ps3s) <- names(pars.i.2ps)[ix.10]
save(mod.sens.fits.2ps3s, file = paste0("../data/derived/modFit_pars/", "mod.fits.2ps3s", "_", Sys.Date(), ".Rdata"))
mod.fits.2ps3s <- lapply(mod.sens.fits.2ps3s, function(x) x[[1]])

### 2p4 (par range set, stock and bulk 14C costs, GPP-based inputs by eco)
## 2pp
# 0-10
mod.sens.fits.2pp4.10 <- mod.fits.fx(mod = "2pp",
                                     pars = pars.i.2pp,
                                     sub = ix.10,
                                     In = in.est,
                                     upper = c(1, .02, .951),
                                     lower = c(.04, .0001, .5),
                                     cost = "14C bulk + cStock")
names(mod.sens.fits.2pp4.10) <- names(pars.i.2pp)[ix.10]
save(mod.sens.fits.2pp4.10, file = paste0("../data/derived/modFit_pars/", "mod.fits.2pp4.10", "_", Sys.Date(), ".Rdata"))
mod.fits.2pp4.10 <- lapply(mod.sens.fits.2pp4.10, function(x) x[[1]])
# 20-30
mod.sens.fits.2pp4.30 <- mod.fits.fx(mod = "2pp",
                                     pars = pars.i.2pp,
                                     sub = ix.30,
                                     In = in.est,
                                     upper = c(1, .02, .951),
                                     lower = c(.04, .0001, .5),
                                     cost = "14C bulk + cStock")
names(mod.sens.fits.2pp4.30) <- names(pars.i.2pp)[ix.30]
save(mod.sens.fits.2pp4.30, file = paste0("../data/derived/modFit_pars/", "mod.fits.2pp4.30", "_", Sys.Date(), ".Rdata"))
mod.fits.2pp4.30 <- lapply(mod.sens.fits.2pp4.30, function(x) x[[1]])
## 2ps
# 0-10
mod.sens.fits.2ps4.10 <- mod.fits.fx(mod = "2ps",
                                     pars = pars.i.2ps,
                                     sub = ix.10,
                                     In = in.est,
                                     upper = c(1, .02, .1),
                                     lower = c(.04, .0001, 0),
                                     cost = "14C bulk + cStock")
names(mod.sens.fits.2ps4.10) <- names(pars.i.2ps)[ix.10]
save(mod.sens.fits.2ps4.10, file = paste0("../data/derived/modFit_pars/", "mod.fits.2ps4.10", "_", Sys.Date(), ".Rdata"))
mod.fits.2ps4.10 <- lapply(mod.sens.fits.2ps4.10, function(x) x[[1]])
# 20-30
mod.sens.fits.2ps4.30 <- mod.fits.fx(mod = "2ps",
                                     pars = pars.i.2ps,
                                     sub = ix.30,
                                     In = in.est,
                                     upper = c(1, .02, .1),
                                     lower = c(.04, .0001, 0),
                                     cost = "14C bulk + cStock")
names(mod.sens.fits.2ps4.30) <- names(pars.i.2ps)[ix.30]
save(mod.sens.fits.2ps4.30, file = paste0("../data/derived/modFit_pars/", "mod.fits.2ps4.30", "_", Sys.Date(), ".Rdata"))
mod.fits.2ps4.30 <- lapply(mod.sens.fits.2ps4.30, function(x) x[[1]])

### 2p4r (par range set, stock, bulk, and respiration 14C costs, GPP-based inputs by eco)
## 2pp
# 0-10
mod.sens.fits.2pp4r.10 <- mod.fits.fx(mod = "2pp",
                                      pars = pars.i.2pp,
                                      sub = ix.10,
                                      In = in.est,
                                      upper = c(1, .02, .951),
                                      lower = c(.04, .0001, .5),
                                      cost = "14C + cStock")
names(mod.sens.fits.2pp4r.10) <- names(pars.i.2pp)[ix.10]
save(mod.sens.fits.2pp4r.10, file = paste0("../data/derived/modFit_pars/", "mod.fits.2pp4r.10", "_", Sys.Date(), ".Rdata"))
mod.fits.2pp4r.10 <- lapply(mod.sens.fits.2pp4r.10, function(x) x[[1]])
# 20-30
mod.sens.fits.2pp4r.30 <- mod.fits.fx(mod = "2pp",
                                      pars = pars.i.2pp,
                                      sub = ix.30,
                                      In = in.est,
                                      upper = c(1, .02, .951),
                                      lower = c(.04, .0001, .5),
                                      cost = "14C + cStock")
names(mod.sens.fits.2pp4r.30) <- names(pars.i.2pp)[ix.30]
save(mod.sens.fits.2pp4r.30, file = paste0("../data/derived/modFit_pars/", "mod.fits.2pp4r.30", "_", Sys.Date(), ".Rdata"))
mod.fits.2pp4r.30 <- lapply(mod.sens.fits.2pp4r.30, function(x) x[[1]])
## 2ps
# 0-10
mod.sens.fits.2ps4r.10 <- mod.fits.fx(mod = "2ps",
                                      pars = pars.i.2ps,
                                      sub = ix.10,
                                      In = in.est,
                                      upper = c(1, .02, .1),
                                      lower = c(.04, .0001, 0),
                                      cost = "14C + cStock")
names(mod.sens.fits.2ps4r.10) <- names(pars.i.2ps)[ix.10]
save(mod.sens.fits.2ps4r.10, file = paste0("../data/derived/modFit_pars/", "mod.fits.2ps4r.10", "_", Sys.Date(), ".Rdata"))
mod.fits.2ps4r.10 <- lapply(mod.sens.fits.2ps4r.10, function(x) x[[1]])
# 20-30
mod.sens.fits.2ps4r.30 <- mod.fits.fx(mod = "2ps",
                                      pars = pars.i.2ps,
                                      sub = ix.30,
                                      In = in.est,
                                      upper = c(1, .02, .1),
                                      lower = c(.04, .0001, 0),
                                      cost = "14C + cStock")
names(mod.sens.fits.2ps4r.30) <- names(pars.i.2ps)[ix.30]
save(mod.sens.fits.2ps4r.30, file = paste0("../data/derived/modFit_pars/", "mod.fits.2ps4r.30", "_", Sys.Date(), ".Rdata"))
mod.fits.2ps4r.30 <- lapply(mod.sens.fits.2ps4r.30, function(x) x[[1]])
# load initial parameters as needed
if (!exists("pars.i.2pp")) {
 load("../data/derived/modFit_pars/pars.i.2pp_2020-11-16.Rdata") 
}
if (!exists("pars.i.2ps")) {
  load("../data/derived/modFit_pars/pars.i.2ps_2020-11-16.Rdata")  
}

# load fits as needed
if (!exists("mod.fits.2pp")) {
 load(file = "../data/derived/modFit_pars/mod.fits.2pp_2020-11-16.RData")
}
if (!exists("mod.fits.2pp.p3.5.95")) {
  load("../data/derived/modFit_pars/mod.fits.2pp.p3.5.95_2020-11-16.Rdata")  
}
if (!exists("mod.fits.2ps")) {
 load(file = "../data/derived/modFit_pars/mod.fits.2ps_2020-11-16.Rdata")
}
if (!exists("mod.fits.2pp2")) {
 load(file = "../data/derived/modFit_pars/mod.fits.2pp.flx.stock_2020-12-02.RData")
}
if (!exists("mod.fits.2ps2")) {
 load(file = "../data/derived/modFit_pars/mod.fits.2ps.flx.stock_2020-12-02.Rdata")
}
if (!exists("mod.fits.2pp3")) {
 load(file = "../data/derived/modFit_pars/mod.fits.2pp3_2020-12-08.RData")
}
if (!exists("mod.fits.2ps3")) {
 load(file = "../data/derived/modFit_pars/mod.fits.2ps3_2020-12-08.Rdata")
}
if (!exists("mod.fits.2pp3s")) {
 load(file = "../data/derived/modFit_pars/mod.fits.2pp3s_2020-12-08.RData")
}
if (!exists("mod.fits.2ps3s")) {
 load(file = "../data/derived/modFit_pars/mod.fits.2ps3s_2020-12-08.Rdata")
}

## Par estimates
# 2pp
pars.fit.2pp <- lapply(mod.fits.2pp, "[[", 1)
names(pars.fit.2pp) <- names(pars.i.2pp)[ix.10]
# 2pp gam = [.5, .95]
pars.fit.2pp.p3.5.95 <- lapply(mod.fits.2pp.p3.5.95, "[[", 1)
names(pars.fit.2pp.p3.5.95) <- names(pars.i.2pp)[ix.10]

# 2ps
pars.fit.2ps <- lapply(mod.fits.2ps, "[[", 1)
names(pars.fit.2ps) <- names(pars.i.2ps)[ix.10]


# 2pp2 (input/stock and 14C constraints)
pars.fit.2pp2 <- lapply(mod.fits.2pp2, "[[", 1)
names(pars.fit.2pp2) <- names(pars.i.2pp)[ix.10]
# 2ps2 (input/stock and 14C constraints)
pars.fit.2ps2 <- lapply(mod.fits.2ps2, "[[", 1)
names(pars.fit.2ps2) <- names(pars.i.2ps)[ix.10]

# 2pp3 (14C constraints, constrained par ranges, stock-fit inputs)
pars.fit.2pp3 <- lapply(mod.fits.2pp3, "[[", 1)
Error in lapply(mod.fits.2pp3, "[[", 1) : 
  object 'mod.fits.2pp3' not found
## look at sensFun output
# without constraints
sens.2pp <- lapply(mod.sens.fits.2pp, function(x) x[[2]])
sens.2ps <- lapply(mod.sens.fits.2ps, function(x) x[[2]])
# without stock constraint
sens.2pp3 <- lapply(mod.sens.fits.2pp3, function(x) x[[2]])
sens.2ps3 <- lapply(mod.sens.fits.2ps3, function(x) x[[2]])
# with stock constraint
sens.2pp3s <- lapply(mod.sens.fits.2pp3s, function(x) x[[2]])
sens.2ps3s <- lapply(mod.sens.fits.2ps3s, function(x) x[[2]])
# with stock constraint, w/o resp
sens.2pp4.10 <- lapply(mod.sens.fits.2pp4.10, function(x) x[[2]])
sens.2pp4.30 <- lapply(mod.sens.fits.2pp4.30, function(x) x[[2]])
sens.2ps4.10 <- lapply(mod.sens.fits.2ps4.10, function(x) x[[2]])
sens.2ps4.30 <- lapply(mod.sens.fits.2ps4.30, function(x) x[[2]])
# with stock constraint + resp
sens.2pp4r.10 <- lapply(mod.sens.fits.2pp4r.10, function(x) x[[2]])
sens.2pp4r.30 <- lapply(mod.sens.fits.2pp4r.30, function(x) x[[2]])
sens.2ps4r.10 <- lapply(mod.sens.fits.2ps4r.10, function(x) x[[2]])
sens.2ps4r.30 <- lapply(mod.sens.fits.2ps4r.30, function(x) x[[2]])


# plot sensitivity
# w/o constraints
lapply(sens.2pp, function(x) plot(x, which = c("bulkC", "resp")))
lapply(sens.2ps, function(x) plot(x, which = c("bulkC", "resp")))
# w/o stock constraint
lapply(sens.2pp3, function(x) plot(x, which = c("bulkC", "cStock")))
lapply(sens.2ps3, function(x) plot(x, which = c("bulkC", "cStock")))
lapply(sens.2pp3s, function(x) plot(x, which = c("bulkC", "cStock")))
lapply(sens.2ps3s, function(x) plot(x, which = c("bulkC", "cStock")))
# with stock constraint, w/o resp
lapply(sens.2pp4.10, function(x) plot(x, which = c("bulkC", "cStock")))
lapply(sens.2pp4.30, function(x) plot(x, which = c("bulkC", "cStock")))
lapply(sens.2ps4.10, function(x) plot(x, which = c("bulkC", "cStock")))
lapply(sens.2ps4.30, function(x) plot(x, which = c("bulkC", "cStock")))
# with stock constraint + resp
lapply(sens.2pp4r.10, function(x) plot(x, which = c("bulkC", "cStock")))
lapply(sens.2pp4r.30, function(x) plot(x, which = c("bulkC", "cStock")))
lapply(sens.2ps4r.10, function(x) plot(x, which = c("bulkC", "cStock")))
lapply(sens.2ps4r.30, function(x) plot(x, which = c("bulkC", "cStock")))


# look at identifiability
inden.df.fx <- function(ls, mod) {
  lapply(ls, function(x) {
    df <- collin(x)
    if (mod == "2pp") {
      df$ParCombo <- factor(c("k1 + k2", "k1 + gam", "k2 + gam", "k1 + k2 + gam"))
    } else {
      df$ParCombo <- factor(c("k1 + k2", "k1 + a21", "k2 + a21", "k1 + k2 + a21"))
    }
    return(df)
  })
}

iden.2pp <- inden.df.fx(sens.2pp, mod = "2pp")
iden.2ps <- inden.df.fx(sens.2ps, mod = "2ps")
iden.2pp3 <- inden.df.fx(sens.2pp3, mod = "2pp")
iden.2ps3 <- inden.df.fx(sens.2ps3, mod = "2ps")
iden.2pp3s <- inden.df.fx(sens.2pp3s, mod = "2pp")
iden.2ps3s <- inden.df.fx(sens.2ps3s, mod = "2ps")
# with stock constraint, w/o resp
iden.2pp4.10 <- inden.df.fx(sens.2pp4.10, mod = "2pp")
iden.2pp4.30 <- inden.df.fx(sens.2pp4.30, mod = "2pp")
iden.2ps4.10 <- inden.df.fx(sens.2ps4.10, mod = "2ps")
iden.2ps4.30 <- inden.df.fx(sens.2ps4.30, mod = "2ps")
# with stock constraint + resp
iden.2pp4r.10 <- inden.df.fx(sens.2pp4r.10, mod = "2pp")
iden.2pp4r.30 <- inden.df.fx(sens.2pp4r.30, mod = "2pp")
iden.2ps4r.10 <- inden.df.fx(sens.2ps4r.10, mod = "2ps")
iden.2ps4r.30 <- inden.df.fx(sens.2ps4r.30, mod = "2ps")

# identifiability plot function
coll.plot.fx <- function(df, mod, PMeco_depth, col.max) {
  ggplot(df, aes(N, log(collinearity), color = ParCombo)) +
    geom_hline(yintercept = log(20)) +
    geom_point(size = 3.5, position = position_dodge(width = .1)) +
    scale_y_continuous(limits = c(0, log(col.max))) +
    scale_x_continuous(limits = c(1.5, 3.5), breaks = c(2, 3)) +
    labs(title = paste(PMeco_depth, mod)) +
    theme_bw() +
    theme(panel.grid = element_blank()) +
    if (mod == "2pp" | mod == "2pp + stock") {
     scale_color_manual(
       name = "Parameter combination",
       values = c("k1 + k2" = "#EF476F",
                  "k1 + gam" = "#FFD166",
                  "k2 + gam" = "#118AB2",
                  "k1 + k2 + gam" = "073B4C")) 
    } else {
      scale_color_manual(
        name = "Parameter combination",
        values = c("k1 + k2" = "#EF476F",
                  "k1 + a21" = "#FFD166",
                  "k2 + a21" = "#118AB2",
                  "k1 + k2 + a21" = "073B4C"))
    }
}
lapply(seq_along(iden.2pp), function(i) {
  coll.plot.fx(iden.2pp[[i]], mod = "2pp", names(iden.2pp)[i], max(iden.2pp[[i]]["collinearity"]))
})
lapply(seq_along(iden.2ps), function(i) {
  coll.plot.fx(iden.2ps[[i]], mod = "2ps", names(iden.2ps)[i], max(iden.2ps[[i]]["collinearity"]))
})
lapply(seq_along(iden.2pp3), function(i) {
  coll.plot.fx(iden.2pp3[[i]], mod = "2pp", names(iden.2pp3)[i])
})
lapply(seq_along(iden.2pp3s), function(i) {
  coll.plot.fx(iden.2pp3s[[i]], mod = "2pp + stock", names(iden.2pp3s)[i])
})
lapply(seq_along(iden.2ps3), function(i) {
  coll.plot.fx(iden.2ps3[[i]], mod = "2ps", names(iden.2ps3)[i])
})
lapply(seq_along(iden.2ps3s), function(i) {
  coll.plot.fx(iden.2ps3s[[i]], mod = "2ps + stock", names(iden.2ps3s)[i])
})
# stock constraint, w/o resp
col.max <- max(unlist(list(lapply(iden.2ps4.10, function(df) df[["collinearity"]]),
                           lapply(iden.2ps4.30, function(df) df[["collinearity"]]),
                           lapply(iden.2pp4.10, function(df) df[["collinearity"]]),
                           lapply(iden.2pp4.30, function(df) df[["collinearity"]]))))
lapply(seq_along(iden.2ps4.10), function(i) {
  coll.plot.fx(iden.2ps4.10[[i]], mod = "2ps + stock", names(iden.2ps4.10)[i], col.max)
})
lapply(seq_along(iden.2ps4.30), function(i) {
  coll.plot.fx(iden.2ps4.30[[i]], mod = "2ps + stock", names(iden.2ps4.30)[i], col.max)
})
lapply(seq_along(iden.2pp4.10), function(i) {
  coll.plot.fx(iden.2pp4.10[[i]], mod = "2pp + stock", names(iden.2pp4.10)[i], col.max)
})
lapply(seq_along(iden.2pp4.30), function(i) {
  coll.plot.fx(iden.2pp4.30[[i]], mod = "2pp + stock", names(iden.2pp4.30)[i], col.max)
})

# stock constraint + resp
col.max.r <- max(unlist(list(lapply(iden.2ps4r.10, function(df) df[["collinearity"]]),
                             lapply(iden.2ps4r.30, function(df) df[["collinearity"]]),
                             lapply(iden.2pp4r.10, function(df) df[["collinearity"]]),
                             lapply(iden.2pp4r.30, function(df) df[["collinearity"]]))))
lapply(seq_along(iden.2pp4r.10), function(i) {
  coll.plot.fx(iden.2pp4r.10[[i]], mod = "2pp", names(iden.2pp4r.10)[i], col.max)
})
lapply(seq_along(iden.2pp4r.30), function(i) {
  coll.plot.fx(iden.2pp4r.30[[i]], mod = "2ps", names(iden.2pp4r.30)[i], col.max)
})
lapply(seq_along(iden.2ps4r.10), function(i) {
  coll.plot.fx(iden.2ps4r.10[[i]], mod = "2ps + stock", names(iden.2ps4r.10)[i], col.max)
})
lapply(seq_along(iden.2ps4r.30), function(i) {
  coll.plot.fx(iden.2ps4r.30[[i]], mod = "2ps + stock", names(iden.2ps4r.30)[i], col.max)
})
## plot pars
par.plot.fx <- function(mod, depth, par.df, initial = FALSE) {
  par.df %>%
    { if (initial == TRUE) . else filter(., est == "fit") } %>%
    filter(depth == depth) %>%
    pivot_longer(!(est:depth), names_to = "par", values_to = "value") %>%
    mutate(PM = factor(PM),
           eco = factor(eco, levels = c("pp", "wf", "rf"))) %>%
    ggplot(., aes(par, value, color = PM, shape = eco)) +
    # geom_jitter(size = 4) +
    geom_point(size = 4, position = position_dodge(width = .5)) +
    scale_color_manual(name = "parent material",
                      labels = c("AN" = "andesite",
                                 "BS" = "basalt",
                                 "GR" = "granite"),
                      values = c("AN" = "blue", 
                                 "BS" = "red", 
                                 "GR" = "darkgray")) +
    facet_wrap(. ~ par, scales = "free") +
    ggtitle(paste0("modFit pars ", mod, " ", depth)) +
    theme_bw() +
    theme(panel.grid.minor = element_blank())
}
# 0-10
# 2pp
par.plot.fx(mod = "2pp",
            depth = "0-10",
            par.df = pars.fit.2pp.df,
            initial = FALSE)
# 2pp, gam = [.5,.95]
par.plot.fx(mod = "2pp (gam = [0.5, 0.95])",
            depth = "0-10",
            par.df = pars.fit.2pp.p3.5.95.df,
            initial = FALSE)
# 2pp2
par.plot.fx(mod = "2pp2",
            depth = "0-10",
            par.df = pars.fit.2pp2.df,
            initial = FALSE)
# 2ps
par.plot.fx(mod = "2ps",
            depth = "0-10",
            par.df = pars.fit.2ps.df,
            initial = FALSE)
# 2ps2
par.plot.fx(mod = "2ps2",
            depth = "0-10",
            par.df = pars.fit.2ps2.df,
            initial = FALSE)

# w/ and w/o stock constraint
par.plot.fx(mod = "2pp3",
            depth = "0-10",
            par.df = pars.fit.2pp3.df,
            initial = FALSE)
par.plot.fx(mod = "2pp3s",
            depth = "0-10",
            par.df = pars.fit.2pp3s.df,
            initial = FALSE)
par.plot.fx(mod = "2ps3",
            depth = "0-10",
            par.df = pars.fit.2ps3.df,
            initial = FALSE)
par.plot.fx(mod = "2ps3s",
            depth = "0-10",
            par.df = pars.fit.2ps3s.df,
            initial = FALSE)

## flux est inputs by eco
# stock and bulk 14C only
par.plot.fx(mod = "2pp4",
            depth = "0-10",
            par.df = pars.fit.2pp4.10.df,
            initial = FALSE)
par.plot.fx(mod = "2pp4",
            depth = "20-30",
            par.df = pars.fit.2pp4.30.df,
            initial = FALSE)
par.plot.fx(mod = "2ps4",
            depth = "0-10",
            par.df = pars.fit.2ps4.10.df,
            initial = FALSE)
par.plot.fx(mod = "2ps4",
            depth = "20-30",
            par.df = pars.fit.2ps4.30.df,
            initial = FALSE)

# stock and bulk + resp 14C
par.plot.fx(mod = "2pp4r",
            depth = "0-10",
            par.df = pars.fit.2pp4r.10.df,
            initial = FALSE)
par.plot.fx(mod = "2pp4r",
            depth = "20-30",
            par.df = pars.fit.2pp4r.30.df,
            initial = FALSE)
par.plot.fx(mod = "2ps4r",
            depth = "0-10",
            par.df = pars.fit.2ps4r.10.df,
            initial = FALSE)
par.plot.fx(mod = "2ps4r",
            depth = "20-30",
            par.df = pars.fit.2ps4r.30.df,
            initial = FALSE)
## Find best inputs
# 2pp
in.fit.2pp <- lapply(seq_along(pars.fit.2pp), function(i) {
  PMeco_depth <- names(pars.fit.2pp)[i]
  SOC <- csoc.19.0_30[[PMeco_depth]][ ,"lyr_soc"]
  return(in.fit.fx("2pp", pars.fit.2pp[[i]], in.i[ix.10][[i]], SOC))
})
names(in.fit.2pp) <- names(mod.fits.2pp)
# 2pp gam = [.5, .95]
in.fit.2pp.p3.5.95 <- lapply(seq_along(pars.fit.2pp.p3.5.95), function(i) {
  PMeco_depth <- names(pars.fit.2pp.p3.5.95)[i]
  SOC <- csoc.19.0_30[[PMeco_depth]][ ,"lyr_soc"]
  return(in.fit.fx("2pp", pars.fit.2pp.p3.5.95[[i]], in.i[ix.10][[i]], SOC))
})
names(in.fit.2pp.p3.5.95) <- names(mod.fits.2pp.p3.5.95)
# 2pp2
in.fit.2pp2 <- lapply(seq_along(pars.fit.2pp2), function(i) {
  PMeco_depth <- names(pars.fit.2pp2)[i]
  SOC <- csoc.19.0_30[[PMeco_depth]][ ,"lyr_soc"]
  return(in.fit.fx("2pp", pars.fit.2pp2[[i]], in.flx.stock[[i]], SOC))
})
names(in.fit.2pp2) <- names(mod.fits.2pp2)
# 2ps
in.fit.2ps <- lapply(seq_along(pars.fit.2ps), function(i) {
  PMeco_depth <- names(pars.fit.2ps)[i]
  SOC <- csoc.19.0_30[[PMeco_depth]][ ,"lyr_soc"]
  return(in.fit.fx("2ps", pars.fit.2ps[[i]], in.i[ix.10][[i]], SOC))
})
names(in.fit.2ps) <- names(mod.fits.2ps)
# 2ps2
in.fit.2ps2 <- lapply(seq_along(pars.fit.2ps2), function(i) {
  PMeco_depth <- names(pars.fit.2ps2)[i]
  SOC <- csoc.19.0_30[[PMeco_depth]][ ,"lyr_soc"]
  return(in.fit.fx("2ps", pars.fit.2ps2[[i]], in.flx.stock[[i]], SOC))
})
names(in.fit.2ps2) <- names(mod.fits.2ps2)

## Calc modeled stocks and compare with measured stocks
# 2pp
mod.socs.2pp.ls <- lapply(seq_along(pars.fit.2pp), function(i) {
  soc.fx("2pp", pars.fit.2pp[[i]], in.fit.2pp[[i]])
})
names(mod.socs.2pp.ls) <- names(pars.fit.2pp)
socs.2pp.ls <- mapply(cbind,
                      csoc.19.0_30[ix.10], 
                      lapply(mod.socs.2pp.ls, colSums), 
                      SIMPLIFY = FALSE)
# 2pp gam = [.5, .95]
mod.socs.2pp.p3.5.95.ls <- lapply(seq_along(pars.fit.2pp.p3.5.95), function(i) {
  soc.fx("2pp", pars.fit.2pp.p3.5.95[[i]], in.fit.2pp.p3.5.95[[i]])
})
names(mod.socs.2pp.p3.5.95.ls) <- names(pars.fit.2pp.p3.5.95)
socs.2pp.p3.5.95ls <- mapply(cbind,
                             csoc.19.0_30[ix.10], 
                             lapply(mod.socs.2pp.p3.5.95.ls, colSums), 
                             SIMPLIFY = FALSE)
# 2pp2
mod.socs.2pp2.ls <- lapply(seq_along(pars.fit.2pp2), function(i) {
  soc.fx("2pp", pars.fit.2pp2[[i]], in.fit.2pp2[[i]])
})
names(mod.socs.2pp2.ls) <- names(pars.fit.2pp2)

# 2ps
mod.socs.2ps.ls <- lapply(seq_along(pars.fit.2ps), function(i) {
  soc.fx("2ps", pars.fit.2ps[[i]], in.fit.2ps[[i]])
})
names(mod.socs.2ps.ls) <- names(pars.fit.2ps)
socs.2ps.ls <- mapply(cbind,
                      csoc.19.0_30[ix.10], 
                      lapply(mod.socs.2ps.ls, colSums), 
                      SIMPLIFY = FALSE)
# 2ps2
mod.socs.2ps2.ls <- lapply(seq_along(pars.fit.2ps2), function(i) {
  soc.fx("2ps", pars.fit.2ps2[[i]], in.fit.2ps2[[i]])
})
names(mod.socs.2ps2.ls) <- names(pars.fit.2ps2)

## stock and bulk 14C costs only
# 2pp
mod.socs.2pp4.10.ls <- lapply(seq_along(pars.fit.2pp4.10), function(i) {
  soc.fx("2pp", pars.fit.2pp4.10[[i]], in.est[ix.10][[i]])
})
names(mod.socs.2pp4.10.ls) <- names(pars.fit.2pp4.10)
mod.socs.2pp4.30.ls <- lapply(seq_along(pars.fit.2pp4.30), function(i) {
  soc.fx("2pp", pars.fit.2pp4.30[[i]], in.est[ix.30][[i]])
})
names(mod.socs.2pp4.30.ls) <- names(pars.fit.2pp4.30)
# 2ps
mod.socs.2ps4.10.ls <- lapply(seq_along(pars.fit.2ps4.10), function(i) {
  soc.fx("2ps", pars.fit.2ps4.10[[i]], in.est[ix.10][[i]])
})
names(mod.socs.2ps4.10.ls) <- names(pars.fit.2ps4.10)
mod.socs.2ps4.30.ls <- lapply(seq_along(pars.fit.2ps4.30), function(i) {
  soc.fx("2ps", pars.fit.2ps4.30[[i]], in.est[ix.30][[i]])
})
names(mod.socs.2ps4.30.ls) <- names(pars.fit.2ps4.30)

## stock and bulk + resp 14C costs
# 2pp
mod.socs.2pp4r.10.ls <- lapply(seq_along(pars.fit.2pp4r.10), function(i) {
  soc.fx("2pp", pars.fit.2pp4r.10[[i]], in.est[ix.10][[i]])
})
names(mod.socs.2pp4r.10.ls) <- names(pars.fit.2pp4r.10)
mod.socs.2pp4r.30.ls <- lapply(seq_along(pars.fit.2pp4r.30), function(i) {
  soc.fx("2pp", pars.fit.2pp4r.30[[i]], in.est[ix.30][[i]])
})
names(mod.socs.2pp4r.30.ls) <- names(pars.fit.2pp4r.30)
# 2ps
mod.socs.2ps4r.10.ls <- lapply(seq_along(pars.fit.2ps4r.10), function(i) {
  soc.fx("2ps", pars.fit.2ps4r.10[[i]], in.est[ix.10][[i]])
})
names(mod.socs.2ps4r.10.ls) <- names(pars.fit.2ps4r.10)
mod.socs.2ps4r.30.ls <- lapply(seq_along(pars.fit.2ps4r.30), function(i) {
  soc.fx("2ps", pars.fit.2ps4r.30[[i]], in.est[ix.30][[i]])
})
names(mod.socs.2ps4r.30.ls) <- names(pars.fit.2ps4r.30)


## Return data frames of model fits with adjusted inputs and optimal parameters
# 2pp
Twopp.fits <- lapply(seq_along(pars.fit.2pp), function(i) {
  par.fx(pars.fit.2pp[[i]], in.fit.2pp[[i]], verbose = FALSE, mod = "2pp")
})
names(Twopp.fits) <- names(pars.fit.2pp)
# 2pp gam = [.5, .95]
Twopp.p3.5.95.fits <- lapply(seq_along(pars.fit.2pp.p3.5.95), function(i) {
  par.fx(pars.fit.2pp.p3.5.95[[i]], in.fit.2pp.p3.5.95[[i]], verbose = FALSE, mod = "2pp")
})
names(Twopp.p3.5.95.fits) <- names(pars.fit.2pp.p3.5.95)
# 2pp2
Twopp2.fits <- lapply(seq_along(pars.fit.2pp2), function(i) {
  par.fx(pars.fit.2pp2[[i]], in.fit.2pp2[[i]], verbose = FALSE, mod = "2pp")
})
names(Twopp2.fits) <- names(pars.fit.2pp2)
# 2ps
Twops.fits <- lapply(seq_along(pars.fit.2ps), function(i) {
  par.fx(pars.fit.2ps[[i]], in.fit.2ps[[i]], verbose = FALSE, mod = "2ps")
})
names(Twops.fits) <- names(pars.fit.2ps)
# 2ps2
Twops2.fits <- lapply(seq_along(pars.fit.2ps2), function(i) {
  par.fx(pars.fit.2ps2[[i]], in.fit.2ps2[[i]], verbose = FALSE, mod = "2ps", pass = TRUE)
})
names(Twops2.fits) <- names(pars.fit.2ps2)

## stock and bulk 14C costs only
# 2pp
Twopp4.10.fits <- lapply(seq_along(pars.fit.2pp4.10), function(i) {
  par.fx(pars.fit.2pp4.10[[i]], in.est[ix.10][[i]], verbose = FALSE, mod = "2pp", pass = FALSE)
})
names(Twopp4.10.fits) <- names(pars.fit.2pp4.10)
Twopp4.30.fits <- lapply(seq_along(pars.fit.2pp4.30), function(i) {
  par.fx(pars.fit.2pp4.30[[i]], in.est[ix.30][[i]], verbose = FALSE, mod = "2pp", pass = FALSE)
})
names(Twopp4.30.fits) <- names(pars.fit.2pp4.30)
# 2ps
Twops4.10.fits <- lapply(seq_along(pars.fit.2ps4.10), function(i) {
  par.fx(pars.fit.2ps4.10[[i]], in.est[ix.10][[i]], verbose = FALSE, mod = "2ps", pass = FALSE)
})
names(Twops4.10.fits) <- names(pars.fit.2ps4.10)
Twops4.30.fits <- lapply(seq_along(pars.fit.2ps4.30), function(i) {
  par.fx(pars.fit.2ps4.30[[i]], in.est[ix.30][[i]], verbose = FALSE, mod = "2ps", pass = FALSE)
})
names(Twops4.30.fits) <- names(pars.fit.2ps4.30)

## stock and bulk + resp 14C costs
# 2pp
Twopp4r.10.fits <- lapply(seq_along(pars.fit.2pp4r.10), function(i) {
  par.fx(pars.fit.2pp4r.10[[i]], in.est[ix.10][[i]], verbose = FALSE, mod = "2pp", pass = FALSE)
})
names(Twopp4r.10.fits) <- names(pars.fit.2pp4r.10)
Twopp4r.30.fits <- lapply(seq_along(pars.fit.2pp4r.30), function(i) {
  par.fx(pars.fit.2pp4r.30[[i]], in.est[ix.30][[i]], verbose = FALSE, mod = "2pp", pass = FALSE)
})
names(Twopp4r.30.fits) <- names(pars.fit.2pp4r.30)
# 2ps
Twops4r.10.fits <- lapply(seq_along(pars.fit.2ps4r.10), function(i) {
  par.fx(pars.fit.2ps4r.10[[i]], in.est[ix.10][[i]], verbose = FALSE, mod = "2ps", pass = FALSE)
})
names(Twops4r.10.fits) <- names(pars.fit.2ps4r.10)
Twops4r.30.fits <- lapply(seq_along(pars.fit.2ps4r.30), function(i) {
  par.fx(pars.fit.2ps4r.30[[i]], in.est[ix.30][[i]], verbose = FALSE, mod = "2ps", pass = FALSE)
})
names(Twops4r.30.fits) <- names(pars.fit.2ps4r.30)
# Plot optimized model SOC stocks
mod.socs.df.fx <- function(mod, mod.socs.ls, pools) {
  n <- vapply(mod.socs.ls, nrow, numeric(1))
  return(data.frame(SOC = do.call(rbind, mod.socs.ls),
                    pool = rep(pools, length(mod.socs.ls)),
                    PMeco_depth = rep(names(mod.socs.ls), n),
                    Model = rep(mod, sum(n))))       
}
# run fx
# mod.socs.2p.df <- rbind(mod.socs.df.fx("2pp", mod.socs.2pp.ls, c("fast", "slow"))
#                         ,mod.socs.df.fx("2ps", mod.socs.2ps.ls, c("fast", "slow"))
#                         ,mod.socs.df.fx("2pp [.5,.95]", mod.socs.2pp.p3.5.95.ls, c("fast", "slow"))
#                         ,mod.socs.df.fx("2ps2", mod.socs.2ps2.ls, c("fast", "slow"))
#                         ,mod.socs.df.fx("2pp2", mod.socs.2pp2.ls, c("fast", "slow"))
#                         )
mod.socs.2p.df <- rbind(mod.socs.df.fx("2pp", mod.socs.2pp.ls, c("fast", "slow"))
                        ,mod.socs.df.fx("2ps", mod.socs.2ps.ls, c("fast", "slow"))
                        )


# stocks and bulk 14C only
mod.socs.2p4.10.df <- rbind(mod.socs.df.fx("2pp4 0-10", mod.socs.2pp4.10.ls, c("fast", "slow")), mod.socs.df.fx("2ps4 0-10", mod.socs.2ps4.10.ls, c("fast", "slow")))
mod.socs.2p4.30.df <- rbind(mod.socs.df.fx("2pp4 20-30", mod.socs.2pp4.30.ls, c("fast", "slow")) ,mod.socs.df.fx("2ps4 20-30", mod.socs.2ps4.30.ls, c("fast", "slow")))

# stocks and bulk + resp 14C
mod.socs.2p4r.10.df <- rbind(mod.socs.df.fx("2pp4r 0-10", mod.socs.2pp4r.10.ls, c("fast", "slow")), mod.socs.df.fx("2ps4r 0-10", mod.socs.2ps4r.10.ls, c("fast", "slow")))
mod.socs.2p4r.30.df <- rbind(mod.socs.df.fx("2pp4r 20-30", mod.socs.2pp4r.30.ls, c("fast", "slow")) ,mod.socs.df.fx("2ps4r 20-30", mod.socs.2ps4r.30.ls, c("fast", "slow")))

# combine inputs to compare
# in.fits.df <- pivot_longer(do.call(bind_rows, list(in.fit.2pp,
#                                                 in.fit.2pp.p3.5.95,
#                                                 in.fit.2pp2,
#                                                 in.fit.2ps,
#                                                 in.fit.2ps2)),
#                            everything(),
#                            names_to = "PMeco_depth",
#                            values_to = "inputs")
# in.fits.df$mod <- rep(c("2pp",
#                         "2pp.5.95",
#                         "2pp2",
#                         "2ps",
#                         "2ps2"),
#                       each = 9)
in.fits.df <- pivot_longer(do.call(bind_rows, list(in.fit.2pp,
                                                   in.fit.2ps)),
                           everything(),
                           names_to = "PMeco_depth",
                           values_to = "inputs")
in.fits.df$mod <- rep(c("2pp",
                        "2ps"),
                      each = 9)
                        
## plot stocks
# stock and bulk 14C only
mod.socs.2p4.10.df %>%
  mutate(PM = substr(PMeco_depth, 1, 2),
         eco = factor(substr(PMeco_depth, 3, 4), levels = c("pp", "wf", "rf"))) %>%
  ggplot(., aes(pool, SOC, fill = Model)) +
  geom_col(position = position_dodge()) +
  facet_grid(rows = vars(eco), cols = vars(PM)) +
  theme_bw() +
  theme(panel.grid.minor = element_blank())
mod.socs.2p4.30.df %>%
  mutate(PM = substr(PMeco_depth, 1, 2),
         eco = factor(substr(PMeco_depth, 3, 4), levels = c("pp", "wf", "rf"))) %>%
  ggplot(., aes(pool, SOC, fill = Model)) +
  geom_col(position = position_dodge()) +
  facet_grid(rows = vars(eco), cols = vars(PM)) +
  theme_bw() +
  theme(panel.grid.minor = element_blank())
# stock and bulk + resp 14C
mod.socs.2p4r.10.df %>%
  mutate(PM = substr(PMeco_depth, 1, 2),
         eco = factor(substr(PMeco_depth, 3, 4), levels = c("pp", "wf", "rf"))) %>%
  ggplot(., aes(pool, SOC, fill = Model)) +
  geom_col(position = position_dodge()) +
  facet_grid(rows = vars(eco), cols = vars(PM)) +
  theme_bw() +
  theme(panel.grid.minor = element_blank())
mod.socs.2p4r.30.df %>%
  mutate(PM = substr(PMeco_depth, 1, 2),
         eco = factor(substr(PMeco_depth, 3, 4), levels = c("pp", "wf", "rf"))) %>%
  ggplot(., aes(pool, SOC, fill = Model)) +
  geom_col(position = position_dodge()) +
  facet_grid(rows = vars(eco), cols = vars(PM)) +
  theme_bw() +
  theme(panel.grid.minor = element_blank())

# inputs
in.fits.df %>%
  mutate(PM = substr(PMeco_depth, 1, 2),
         # Model = factor(Model, levels = c("2pp [.5,.95]", "2pp", "2ps")),
         eco = factor(substr(PMeco_depth, 3, 4), levels = c("pp", "wf", "rf"))) %>%
  ggplot(., aes(mod, inputs, fill = mod)) +
  geom_col(position = position_dodge()) +
  facet_grid(rows = vars(eco), cols = vars(PM)) +
  theme_bw() +
  theme(panel.grid.minor = element_blank())
# plot fx
Twop.fit.plot.fx <- function(fit1, fit1.name, fit2, fit2.name, fit3 = NULL, fit3.name = NULL) {
  lapply(seq_along(fit1), function(i) {
    PMeco <- substr(names(fit1)[i], 1, 4)
    lyr_bot <- substr(names(fit1)[i], 
                      nchar(names(fit1)[i]) - 1, 
                      nchar(names(fit1)[i]))
    lyr_top <- ifelse(lyr_bot == 10, 0, ifelse(lyr_bot == 20, 10, 20))
    PMeco_depth <- names(fit1)[i]
    con.df <- con.df.fx(PMeco_depth)
    plot.df <- rbind(fit1[[i]],
                     fit2[[i]],
                     fit3[[i]])
    plot.df$Model <- factor(c(rep(fit1.name, nrow(fit1[[i]])),
                              rep(fit2.name, nrow(fit2[[i]])),
                              rep(fit3.name, nrow(fit3[[i]]))),
                            levels = c(fit1.name, fit2.name, fit3.name))
    return(plot.df %>%
             filter(pool == "bulk C" | pool == "respiration" | pool == "atm") %>%
             ggplot(., aes(years, d14C, color = pool)) +
             geom_path(aes(linetype = Model)) +
             geom_point(data = con.df, aes(Year, d14c, color = pool), size = 3) +
             scale_color_manual(
               name = "Model pool",
               values = c("atm" = 8,
                          "bulk C" = "black",
                          "fast" = "#D81B60",
                          "slow" = "#1E88E5",
                          "respiration" = "#FFC107")) +
             scale_x_continuous(limits = c(1950, 2022)) +
             ggtitle(paste0(PMeco_depth, " 2p mod fits")) +
             xlab("Year") +
             ylab(expression(''*Delta*''^14*'C (‰)')) +
             theme_bw() +
             theme(panel.grid = element_blank()))
  })
}
# 2p modFit optimal model comparison
Twop.fits.plots <- Twop.fit.plot.fx(Twopp.fits, "2pp", Twops.fits, "2ps")
Twop.fits.plots
# Twop.fits.plots2 <- Twop.fit.plot.fx(Twopp.fits, "2pp", Twopp.p3.5.95.fits, "2pp gam = [.5, .95]")
# Twop.fits.plots2
Twop.fits.plots3 <- Twop.fit.plot.fx(Twopp.p3.5.95.fits, "2pp gam = [.5, .95]", Twopp2.fits, "2pp2")
Twop.fits.plots3

## compare fits w/ and w/o resp constraint (2p4 mods)
# 2pp
Twopp4.fits.plots.10 <- Twop.fit.plot.fx(Twopp4.10.fits, "2pp4 0-10cm w/o resp", Twopp4r.10.fits, "2pp4r 0-10cm w/ resp")
Twopp4.fits.plots.30 <- Twop.fit.plot.fx(Twopp4.30.fits, "2pp4 20-30cm w/o resp", Twopp4r.10.fits, "2pp4r 20-30cm w/ resp")
# 2ps
Twops4.fits.plots.10 <- Twop.fit.plot.fx(Twops4.10.fits, "2ps4 0-10cm w/o resp", Twops4r.10.fits, "2ps4r 0-10cm w/ resp")
Twops4.fits.plots.30 <- Twop.fit.plot.fx(Twops4.30.fits, "2ps4 20-30cm w/o resp", Twops4r.10.fits, "2ps4r 20-30cm w/ resp")
# plot
Twopp4.fits.plots.10
Twopp4.fits.plots.30
Twops4.fits.plots.10
Twops4.fits.plots.30
p <- sra.ts.all %>%
    filter(d14c > -200) %>%
    filter(ECO != "rf") %>%
    filter(lyr_bot == 20) %>%
    filter(year != 2009) %>%
    ggplot(., aes(year, d14c)) +
    geom_path(data = atm.14c) +
    geom_point(aes(color = pm, shape = ecoType), size = 3.5) +
    geom_path(aes(color = pm, linetype = Type), size = 1, alpha = 0.3) +
    geom_errorbar(
        aes(ymin = d14c_l, 
            ymax = d14c_u,
            color = pm), 
        width = .5) +
    scale_color_manual(name = "Parent material",
                       values = c("andesite" = "blue", 
                                  "basalt" = "red", 
                                  "granite" = "darkgray")) +
    scale_shape_manual(name = "Ecosystem (type)",
                       values = c("warm (inc)" = 0,
                                  "cool (inc)" = 1,
                                  "cold (inc)" = 2,
                                  "warm (bulk)" = 15,
                                  "cool (bulk)" = 16,
                                  "cold (bulk)" = 17)) +
    facet_grid(rows = vars(eco), cols = vars(pm)) +
    ylab(expression(Delta*''^14*'C (‰)')) +
    xlab("Year") +
    ggtitle("Bulk/inc 10-20 cm") +
    theme_bw() +
    theme(panel.grid = element_blank(),
          axis.text.x = element_text(size = 8))
ggsave("sra.ts.ppwf20.blk.inc.pdf", p, dpi = 300, width = 6.97, height = 5, units = "in")
# inc/bulk profiles
p <- sra.19.01.09 %>%
  filter(lyr_bot < 31) %>%
  select(Year, PM, ECO, PMeco, lyr_bot, d14c, d14c_sd) %>%
  mutate(Type = "bulk",
         d14c_u = d14c + d14c_sd,
         d14c_l = d14c - d14c_sd,
         year = as.numeric(as.character(Year))) %>%
  select(-d14c_sd) %>%
  bind_rows(.,
            sra.19.01.inc %>%
              select(year, PM, ECO, PMeco, lyr_bot, d14c, d14c_min, d14c_max) %>%
              rename(d14c_l = d14c_min,
                     d14c_u = d14c_max) %>%
              mutate(Type = "inc")
  ) %>%
  mutate(depth = factor(lyr_bot),
         eco = factor(ifelse(ECO == "pp", "warm",
                      ifelse(ECO == "wf", "cool", "cold")),
                      levels = c("warm", "cool", "cold")),
         pm = ifelse(PM == "AN", "andesite",
                     ifelse(PM == "BS", "basalt", "granite")),
         ecoType = paste0(eco, " (", Type, ")"))
ggsave("sra.ts.ppwf20.blk.pdf", p, dpi = 300, width = 6.97, height = 5, units = "in")
### Run modfit
## 14C bulk only
# 0-10
mod.sens.fits.2ps.10b <- mod.fits.fx(mod = "2ps",
                                     pars = pars.i.2ps, 
                                     sub = ix.10,
                                     In = in.est,
                                     upper = c(1, .02, .999),
                                     lower = c(.02, .0001, .001),
                                     cost = "14C bulk only")
names(mod.sens.fits.2ps.10b) <- names(pars.i.2ps)[ix.10]
save(mod.sens.fits.2ps.10b, file = paste0("../data/derived/modFit_pars/", "mod.fits.2ps.10b", "_", Sys.Date(), ".Rdata"))
# # 20-30
# mod.sens.fits.2ps.30b <- mod.fits.fx(mod = "2ps",
#                                      pars = pars.i.2ps, 
#                                      sub = ix.30,
#                                      In = in.est,
#                                      upper = c(1, .02, .15),
#                                      lower = c(.005, .0001, .0004),
#                                      cost = "14C bulk only")
# names(mod.sens.fits.2ps.30b) <- names(pars.i.2ps)[ix.30]
# save(mod.sens.fits.2ps.30b, file = paste0("../data/derived/modFit_pars/", "mod.fits.2ps.30b", "_", Sys.Date(), ".Rdata"))
# mod.fits.2ps.30b <- lapply(mod.sens.fits.2ps.30b, function(x) x[[1]])

## 14C (bulk + resp)
# 0-10
mod.sens.fits.2ps.10br <- mod.fits.fx(mod = "2ps",
                                     pars = pars.i.2ps, 
                                     sub = ix.10,
                                     In = in.est,
                                     upper = c(1, .02, .999),
                                     lower = c(.02, .0001, .001),
                                     cost = "14C")
names(mod.sens.fits.2ps.10br) <- names(pars.i.2ps)[ix.10]
save(mod.sens.fits.2ps.10br, file = paste0("../data/derived/modFit_pars/", "mod.fits.2ps.10br", "_", Sys.Date(), ".Rdata"))
# 10-20, lag = 5
mod.sens.fits.2ps.20br.l <- mod.fits.fx(mod = "2ps",
                                       pars = pars.i.2ps,
                                       sub = ix.20,
                                       In = in.est,
                                      lag = 5,
                                       upper = c(1, .02, .99),
                                       lower = c(.02, .0001, .01),
                                       cost = "14C")
names(mod.sens.fits.2ps.20br.l) <- names(pars.i.2ps)[ix.20]
save(mod.sens.fits.2ps.20br.l, file = paste0("../data/derived/modFit_pars/", "mod.fits.2ps.20br.l", "_", Sys.Date(), ".Rdata"))
# # 20-30
# mod.sens.fits.2ps.30br <- mod.fits.fx(mod = "2ps",
#                                      pars = pars.i.2ps, 
#                                      sub = ix.30,
#                                      In = in.est,
#                                      upper = c(1, .02, .15),
#                                      lower = c(.005, .0001, .0004),
#                                      cost = "14C")
# names(mod.sens.fits.2ps.30br) <- names(pars.i.2ps)[ix.30]
# save(mod.sens.fits.2ps.30br, file = paste0("../data/derived/modFit_pars/", "mod.fits.2ps.30br", "_", Sys.Date(), ".Rdata"))
# mod.fits.2ps.30br <- lapply(mod.sens.fits.2ps.30br, function(x) x[[1]])

## 14C bulk + stocks
# 0-10
mod.sens.fits.2ps.10bs <- mod.fits.fx(mod = "2ps",
                                      pars = pars.i.2ps,
                                      sub = ix.10,
                                      In = in.est,
                                      upper = c(1, .02, .999),
                                      lower = c(.02, .0001, .001),
                                      cost = "14C bulk + cStock")
names(mod.sens.fits.2ps.10bs) <- names(pars.i.2ps)[ix.10]
save(mod.sens.fits.2ps.10bs, file = paste0("../data/derived/modFit_pars/", "mod.fits.2ps.10bs", "_", Sys.Date(), ".Rdata"))
mod.fits.2ps.10bs <- lapply(mod.sens.fits.2ps.10bs, function(x) x[[1]])
# # 20-30
# mod.sens.fits.2ps.30b <- mod.fits.fx(mod = "2ps",
#                                      pars = pars.i.2ps, 
#                                      sub = ix.30,
#                                      In = in.est,
#                                      upper = c(1, .02, .15),
#                                      lower = c(.005, .0001, .0004),
#                                      cost = "14C bulk only")
# names(mod.sens.fits.2ps.30b) <- names(pars.i.2ps)[ix.30]
# save(mod.sens.fits.2ps.30b, file = paste0("../data/derived/modFit_pars/", "mod.fits.2ps.30b", "_", Sys.Date(), ".Rdata"))
# mod.fits.2ps.30b <- lapply(mod.sens.fits.2ps.30b, function(x) x[[1]])

## 14C + cStock (14C resp, 14C bulk, stocks)
# 0-10
mod.sens.fits.2ps.10rbs <- mod.fits.fx(mod = "2ps",
                                       pars = pars.i.2ps,
                                       sub = ix.10,
                                       In = in.est,
                                       upper = c(1, .02, .999),
                                       lower = c(.02, .0001, .001),
                                       cost = "14C + cStock")
names(mod.sens.fits.2ps.10rbs) <- names(pars.i.2ps)[ix.10]
save(mod.sens.fits.2ps.10rbs, file = paste0("../data/derived/modFit_pars/", "mod.fits.2ps.10rbs", "_", Sys.Date(), ".Rdata"))
mod.fits.2ps.10rbs <- lapply(mod.sens.fits.2ps.10rbs, function(x) x[[1]])
# 10-20
# w/o lag
mod.sens.fits.2ps.20rbs <- mod.fits.fx(mod = "2ps",
                                       pars = pars.i.2ps,
                                       sub = ix.20,
                                       In = in.est,
                                       upper = c(1, .02, .99),
                                       lower = c(.02, .0001, .01),
                                       cost = "14C + cStock")
names(mod.sens.fits.2ps.20rbs) <- names(pars.i.2ps)[ix.20]
save(mod.sens.fits.2ps.20rbs, file = paste0("../data/derived/modFit_pars/", "mod.fits.2ps.20rbs", "_", Sys.Date(), ".Rdata"))
# w/ lag = 12
mod.sens.fits.2ps.20rbs.l <- mod.fits.fx(mod = "2ps",
                                       pars = pars.i.2ps,
                                       sub = ix.20,
                                       In = in.est,
                                       lag = 12,
                                       upper = c(1, .02, .99),
                                       lower = c(.02, .0001, .01),
                                       cost = "14C + cStock")
names(mod.sens.fits.2ps.20rbs.l) <- names(pars.i.2ps)[ix.20]
save(mod.sens.fits.2ps.20rbs.l, file = paste0("../data/derived/modFit_pars/", "mod.fits.2ps.20rbs.l", "_", Sys.Date(), ".Rdata"))
# # 20-30
# mod.sens.fits.2ps.30b <- mod.fits.fx(mod = "2ps",
#                                      pars = pars.i.2ps, 
#                                      sub = ix.30,
#                                      In = in.est,
#                                      upper = c(1, .02, .15),
#                                      lower = c(.005, .0001, .0004),
#                                      cost = "14C bulk only")
# names(mod.sens.fits.2ps.30b) <- names(pars.i.2ps)[ix.30]
# save(mod.sens.fits.2ps.30b, file = paste0("../data/derived/modFit_pars/", "mod.fits.2ps.30b", "_", Sys.Date(), ".Rdata"))
# mod.fits.2ps.30b <- lapply(mod.sens.fits.2ps.30b, function(x) x[[1]])
# SAB fits
load("../data/derived/modFit_pars/mod.fits.2ps.10b_2021-04-07.Rdata")
load("../data/derived/modFit_pars/mod.fits.2ps.10br_2021-04-07.Rdata")
load("../data/derived/modFit_pars/mod.fits.2ps.10bs_2021-04-07.Rdata")
load("../data/derived/modFit_pars/mod.fits.2ps.10rbs_2021-04-07.Rdata")
load("../data/derived/modFit_pars/mod.fits.2ps.20rbs_2021-04-12.Rdata")
load("../data/derived/modFit_pars/mod.fits.2ps.20rbs.l_2021-04-13.Rdata")
load("../data/derived/modFit_pars/mod.fits.2ps.20br.l_2021-04-13.Rdata")
load("../data/derived/modFit_pars/pars.i.2ps_2021-04-06.Rdata")

# extract mod fits
mod.fits.2ps.10b <- lapply(mod.sens.fits.2ps.10b, function(x) x[[1]])
mod.fits.2ps.10bs <- lapply(mod.sens.fits.2ps.10bs, function(x) x[[1]])
mod.fits.2ps.10br <- lapply(mod.sens.fits.2ps.10br, function(x) x[[1]])
mod.fits.2ps.10rbs <- lapply(mod.sens.fits.2ps.10rbs, function(x) x[[1]])
mod.fits.2ps.20rbs <- lapply(mod.sens.fits.2ps.20rbs, function(x) x[[1]])
mod.fits.2ps.20rbs.l <- lapply(mod.sens.fits.2ps.20rbs.l, function(x) x[[1]])
mod.fits.2ps.20br.l <- lapply(mod.sens.fits.2ps.20br.l, function(x) x[[1]]) 
  
# Sensitivity/Identifiability
#####
# extract at sensFun output
sens.2ps.10b <- lapply(mod.sens.fits.2ps.10b, function(x) x[[2]])
sens.2ps.10br <- lapply(mod.sens.fits.2ps.10br, function(x) x[[2]])
sens.2ps.10bs <- lapply(mod.sens.fits.2ps.10bs, function(x) x[[2]])
sens.2ps.10rbs <- lapply(mod.sens.fits.2ps.10rbs, function(x) x[[2]])
sens.2ps.20rbs <- lapply(mod.sens.fits.2ps.20rbs, function(x) x[[2]])
sens.2ps.20rbs.l <- lapply(mod.sens.fits.2ps.20rbs.l, function(x) x[[2]])
sens.2ps.20br.l <- lapply(mod.sens.fits.2ps.20br.l, function(x) x[[2]])

# plot sensitivity
lapply(sens.2ps.10b, function(x) plot(x, which = c("bulkC", "resp")))
lapply(sens.2ps.10br, function(x) plot(x, which = c("bulkC", "resp")))
lapply(sens.2ps.10bs, function(x) plot(x, which = c("bulkC", "resp")))
lapply(sens.2ps.10rbs, function(x) plot(x, which = c("bulkC", "resp")))

# look at identifiability
iden.2ps.10b <- inden.df.fx(sens.2ps.10b, mod = "2ps")
iden.2ps.10br <- inden.df.fx(sens.2ps.10br, mod = "2ps")
iden.2ps.10bs <- inden.df.fx(sens.2ps.10bs, mod = "2ps")
iden.2ps.10rbs <- inden.df.fx(sens.2ps.10rbs, mod = "2ps")
iden.2ps.20rbs <- inden.df.fx(sens.2ps.20rbs, mod = "2ps")
iden.2ps.20rbs.l <- inden.df.fx(sens.2ps.20rbs.l, mod = "2ps")
iden.2ps.20br.l <- inden.df.fx(sens.2ps.20br.l, mod = "2ps")

# plot
lapply(seq_along(iden.2ps.10bs), function(i) {
  coll.plot.fx(iden.2ps.10bs[[i]], mod = "2ps", 
               names(iden.2ps.10bs)[i], 
               max(iden.2ps.10bs[[i]]["collinearity"]))
})
lapply(seq_along(iden.2ps.10br), function(i) {
  coll.plot.fx(iden.2ps.10br[[i]], mod = "2ps", 
               names(iden.2ps.10br)[i], 
               max(iden.2ps.10br[[i]]["collinearity"]))
})
lapply(seq_along(iden.2ps.10rbs), function(i) {
  coll.plot.fx(iden.2ps.10rbs[[i]], mod = "2ps", 
               names(iden.2ps.10rbs)[i], 
               max(iden.2ps.10rbs[[i]]["collinearity"]))
})
lapply(seq_along(iden.2ps.20rbs), function(i) {
  coll.plot.fx(iden.2ps.20rbs[[i]], mod = "2ps", 
               names(iden.2ps.20rbs)[i], 
               max(iden.2ps.20rbs[[i]]["collinearity"]))
})
lapply(seq_along(iden.2ps.20rbs.l), function(i) {
  coll.plot.fx(iden.2ps.20rbs.l[[i]], mod = "2ps", 
               names(iden.2ps.20rbs.l)[i], 
               max(iden.2ps.20rbs.l[[i]]["collinearity"]))
})
lapply(seq_along(iden.2ps.20br.l), function(i) {
  coll.plot.fx(iden.2ps.20br.l[[i]], mod = "2ps", 
               names(iden.2ps.20br.l)[i], 
               max(iden.2ps.20br.l[[i]]["collinearity"]))
})
#####

# Extract optimized pars from modfit output
#####
## bulk 14c only
# 0-10
pars.fit.2ps.10b <- lapply(mod.fits.2ps.10b, "[[", 1)
names(pars.fit.2ps.10b) <- names(pars.i.2ps)[ix.10]
# # 20-30
# pars.fit.2ps.30b <- lapply(mod.fits.2ps.30b, "[[", 1)
# names(pars.fit.2ps.30b) <- names(pars.i.2ps)[ix.30]

## resp + bulk 14c
# 0-10
pars.fit.2ps.10br <- lapply(mod.fits.2ps.10br, "[[", 1)
names(pars.fit.2ps.10br) <- names(pars.i.2ps)[ix.10]
# 10-20 w/ lag = 5y
pars.fit.2ps.20br.l <- lapply(mod.fits.2ps.20br.l, "[[", 1)
names(pars.fit.2ps.20br.l) <- names(pars.i.2ps)[ix.20]
# # 20-30
# pars.fit.2ps.30br <- lapply(mod.fits.2ps.30br, "[[", 1)
# names(pars.fit.2ps.30br) <- names(pars.i.2ps)[ix.30]

## bulk 14c + stocks
# 0-10
pars.fit.2ps.10bs <- lapply(mod.fits.2ps.10bs, "[[", 1)
names(pars.fit.2ps.10bs) <- names(pars.i.2ps)[ix.10]
# # 20-30
# pars.fit.2ps.30br <- lapply(mod.fits.2ps.30br, "[[", 1)
# names(pars.fit.2ps.30br) <- names(pars.i.2ps)[ix.30]

## resp, bulk 14c, stocks
# 0-10
pars.fit.2ps.10rbs <- lapply(mod.fits.2ps.10rbs, "[[", 1)
names(pars.fit.2ps.10rbs) <- names(pars.i.2ps)[ix.10]
# 10-20
pars.fit.2ps.20rbs <- lapply(mod.fits.2ps.20rbs, "[[", 1)
names(pars.fit.2ps.20rbs) <- names(pars.i.2ps)[ix.20]
# 10-20 w/ lag = 12y
pars.fit.2ps.20rbs.l <- lapply(mod.fits.2ps.20rbs.l, "[[", 1)
names(pars.fit.2ps.20rbs.l) <- names(pars.i.2ps)[ix.20]
# # 20-30
# pars.fit.2ps.30br <- lapply(mod.fits.2ps.30br, "[[", 1)
# names(pars.fit.2ps.30br) <- names(pars.i.2ps)[ix.30]
#####

# SOC stocks
#####
# w/o stock constraint
mod.socs.2ps.10b.ls <- lapply(seq_along(pars.fit.2ps.10b), function(i) {
  soc.fx("2ps", pars.fit.2ps.10b[[i]], in.est[[i]])
})
names(mod.socs.2ps.10b.ls) <- names(pars.fit.2ps.10b)
mod.socs.2ps.10br.ls <- lapply(seq_along(pars.fit.2ps.10br), function(i) {
  soc.fx("2ps", pars.fit.2ps.10br[[i]], in.est[[i]])
})
names(mod.socs.2ps.10br.ls) <- names(pars.fit.2ps.10br)
socs.2ps.10br.ls <- mapply(cbind,
                           csoc.19.0_30[ix.10], 
                           lapply(mod.socs.2ps.10br.ls, colSums), 
                           SIMPLIFY = FALSE)
# w/ stock constraint
mod.socs.2ps.10bs.ls <- lapply(seq_along(pars.fit.2ps.10bs), function(i) {
  soc.fx("2ps", pars.fit.2ps.10bs[[i]], in.est[[i]])
})
names(mod.socs.2ps.10bs.ls) <- names(pars.fit.2ps.10bs)
mod.socs.2ps.10rbs.ls <- lapply(seq_along(pars.fit.2ps.10rbs), function(i) {
  soc.fx("2ps", pars.fit.2ps.10rbs[[i]], in.est[[i]])
})
names(mod.socs.2ps.10rbs.ls) <- names(pars.fit.2ps.10rbs)
mod.socs.2ps.20rbs.ls <- lapply(seq_along(pars.fit.2ps.20rbs), function(i) {
  soc.fx("2ps", pars.fit.2ps.20rbs[[i]], in.est[ix.20][[i]])
})
names(mod.socs.2ps.20rbs.ls) <- names(pars.fit.2ps.20rbs)
socs.2ps.10rbs.ls <- mapply(cbind,
                           csoc.19.0_30[ix.10], 
                           lapply(mod.socs.2ps.10rbs.ls, colSums), 
                           SIMPLIFY = FALSE)

## make df for plotting
# resp + bulk, w/ and w/o stocks
mod.socs.2ps.10brrbs.df <- rbind(mod.socs.df.fx("2ps w/o stock", mod.socs.2ps.10br.ls, c("fast", "slow"))
                                 ,mod.socs.df.fx("2ps w/ stock", mod.socs.2ps.10rbs.ls, c("fast", "slow"))
                                 ,data.frame(SOC = unlist(lapply(csoc.19.0_30[ix.10], "[[", 4)),
                                             PMeco_depth = paste0(
                                               unlist(lapply(csoc.19.0_30[ix.10], "[[", 1)),
                                               "_",
                                               unlist(lapply(csoc.19.0_30[ix.10], "[[", 2)),
                                               "-",
                                               unlist(lapply(csoc.19.0_30[ix.10], "[[", 3))),
                                             Model = "measured",
                                             pool = "total")
                                 )
# bulk + stock, vs. resp, bulk, + stock
mod.socs.2ps.10bsrbs.df <- rbind(mod.socs.df.fx("2ps bulk + stock only", mod.socs.2ps.10bs.ls, c("fast", "slow"))
                                 ,mod.socs.df.fx("2ps bulk, resp, + stock", mod.socs.2ps.10rbs.ls, c("fast", "slow"))
                                 ,data.frame(SOC = unlist(lapply(csoc.19.0_30[ix.10], "[[", 4)),
                                             PMeco_depth = paste0(
                                               unlist(lapply(csoc.19.0_30[ix.10], "[[", 1)),
                                               "_",
                                               unlist(lapply(csoc.19.0_30[ix.10], "[[", 2)),
                                               "-",
                                               unlist(lapply(csoc.19.0_30[ix.10], "[[", 3))),
                                             Model = "measured",
                                             pool = "total")
                                 )


## plot
mod.socs.2ps.10brrbs.df %>%
  mutate(PM = substr(PMeco_depth, 1, 2),
         eco = factor(substr(PMeco_depth, 3, 4), levels = c("pp", "wf", "rf"))) %>%
  ggplot(., aes(pool, SOC, fill = Model)) +
  geom_col(position = position_dodge()) +
  facet_grid(rows = vars(eco), cols = vars(PM)) +
  theme_bw() +
  theme(panel.grid.minor = element_blank())
mod.socs.2ps.10bsrbs.df %>%
  mutate(PM = substr(PMeco_depth, 1, 2),
         eco = factor(substr(PMeco_depth, 3, 4), levels = c("pp", "wf", "rf"))) %>%
  ggplot(., aes(pool, SOC, fill = Model)) +
  geom_col(position = position_dodge()) +
  facet_grid(rows = vars(eco), cols = vars(PM)) +
  theme_bw() +
  theme(panel.grid.minor = element_blank())
#####

### Summarize optimized par data for plotting
## bulk 14c only
# 0-10
pars.fit.2ps.10b.df <- par.fit.df.fx(mod = "2ps",
                                     pars.fit = pars.fit.2ps.10b,
                                     pars.i = pars.i.2ps[ix.10])
# # 20-30
# pars.fit.2ps.30b.df <- par.fit.df.fx(mod = "2ps",
#                                       pars.fit = pars.fit.2ps.30b,
#                                       pars.i = pars.i.2ps[ix.30])

## resp + bulk 14c
# 0-10
pars.fit.2ps.10br.df <- par.fit.df.fx(mod = "2ps",
                                       pars.fit = pars.fit.2ps.10br,
                                       pars.i = pars.i.2ps[ix.10])
# 10-20
pars.fit.2ps.20br.l.df <- par.fit.df.fx(mod = "2ps",
                                       pars.fit = pars.fit.2ps.20br.l,
                                       pars.i = pars.i.2ps[ix.10])
# # 20-30
# pars.fit.2ps.30br.df <- par.fit.df.fx(mod = "2ps",
#                                        pars.fit = pars.fit.2ps.30br,
#                                        pars.i = pars.i.2ps[ix.30])

## bulk 14c + stocks
# 0-10
pars.fit.2ps.10bs.df <- par.fit.df.fx(mod = "2ps",
                                       pars.fit = pars.fit.2ps.10bs,
                                       pars.i = pars.i.2ps[ix.10])
# # 20-30
# pars.fit.2ps.30br.df <- par.fit.df.fx(mod = "2ps",
#                                        pars.fit = pars.fit.2ps.30br,
#                                        pars.i = pars.i.2ps[ix.30])

## resp, bulk, stocks
# 0-10
pars.fit.2ps.10rbs.df <- par.fit.df.fx(mod = "2ps",
                                       pars.fit = pars.fit.2ps.10rbs,
                                       pars.i = pars.i.2ps[ix.10])
# 10-20
pars.fit.2ps.20rbs.df <- par.fit.df.fx(mod = "2ps",
                                       pars.fit = pars.fit.2ps.20rbs,
                                       pars.i = pars.i.2ps[ix.20])
# w/ lag
pars.fit.2ps.20rbs.l.df <- par.fit.df.fx(mod = "2ps",
                                       pars.fit = pars.fit.2ps.20rbs.l,
                                       pars.i = pars.i.2ps[ix.20])
# # 20-30
# pars.fit.2ps.30br.df <- par.fit.df.fx(mod = "2ps",
#                                        pars.fit = pars.fit.2ps.30br,
#                                        pars.i = pars.i.2ps[ix.30])

### Par fits
par.plot.fx(mod = "2ps bulk 14c",
            depth = "0-10",
            par.df = pars.fit.2ps.10b.df,
            initial = FALSE)
par.plot.fx(mod = "2ps resp + bulk 14c",
            depth = "0-10",
            par.df = pars.fit.2ps.10br.df,
            initial = FALSE)
par.plot.fx(mod = "2ps bulk 14c + stocks",
            depth = "0-10",
            par.df = pars.fit.2ps.10bs.df,
            initial = FALSE)
par.plot.fx(mod = "2ps resp, bulk, stocks",
            depth = "0-10",
            par.df = pars.fit.2ps.10rbs.df,
            initial = FALSE)
par.plot.fx(mod = "2ps resp, bulk, stocks",
            depth = "10-20",
            par.df = pars.fit.2ps.20rbs.df,
            initial = FALSE)
par.plot.fx(mod = "2ps resp, bulk, stocks",
            depth = "10-20",
            par.df = pars.fit.2ps.20rbs.l.df,
            initial = FALSE)
par.plot.fx(mod = "2ps resp, bulk",
            depth = "10-20",
            par.df = pars.fit.2ps.20br.l.df,
            initial = FALSE)
# par.plot.fx(mod = "2ps bulk 14c",
#             depth = "20-30",
#             par.df = pars.fit.2ps.30b.df,
#             initial = FALSE)
# par.plot.fx(mod = "2ps resp + bulk 14c",
#             depth = "20-30",
#             par.df = pars.fit.2ps.30br.df,
#             initial = FALSE)

### Fit models with optimized pars
## bulk 14C only
# 0-10
Twops.10b.fits <- lapply(seq_along(pars.fit.2ps.10b), function(i) {
  tryCatch(
    par.fx(pars.fit.2ps.10b[[i]], in.est[ix.10][[i]], verbose = FALSE, mod = "2ps", pass = FALSE),
    error = function (e) {cat("ERROR :", conditionMessage(e), "\n")})
})
names(Twops.10b.fits) <- names(pars.fit.2ps.10b)
# # 20-30
# Twops.30b.fits <- lapply(seq_along(pars.fit.2ps.30b), function(i) {
#   tryCatch(
#     par.fx(pars.fit.2ps.30b[[i]], in.est[ix.30][[i]], verbose = FALSE, mod = "2ps", pass = FALSE),
#     error = function (e) {cat("ERROR :", conditionMessage(e), "\n")})
# })
# names(Twops.30b.fits) <- names(pars.fit.2ps.30b)

## resp + bulk 14C
# 0-10
Twops.10br.fits <- lapply(seq_along(pars.fit.2ps.10br), function(i) {
  tryCatch(
    par.fx(pars.fit.2ps.10br[[i]], in.est[ix.10][[i]], verbose = FALSE, mod = "2ps", pass = FALSE),
    error = function (e) {cat("ERROR :", conditionMessage(e), "\n")})
})
names(Twops.10br.fits) <- names(pars.fit.2ps.10br)
# 10-20
Twops.20br.l.fits <- lapply(seq_along(pars.fit.2ps.20br.l), function(i) {
  tryCatch(
    par.fx(pars.fit.2ps.20br.l[[i]], in.est[ix.10][[i]], verbose = FALSE, mod = "2ps", pass = FALSE),
    error = function (e) {cat("ERROR :", conditionMessage(e), "\n")})
})
names(Twops.20br.l.fits) <- names(pars.fit.2ps.20br.l)
# # 20-30
# Twops.30br.fits <- lapply(seq_along(pars.fit.2ps.30br), function(i) {
#   tryCatch(
#     par.fx(pars.fit.2ps.30br[[i]], in.est[ix.30][[i]], verbose = FALSE, mod = "2ps", pass = FALSE),
#     error = function (e) {cat("ERROR :", conditionMessage(e), "\n")})
# })
# names(Twops.30br.fits) <- names(pars.fit.2ps.30br)

## bulk 14C + stocks
# 0-10
Twops.10bs.fits <- lapply(seq_along(pars.fit.2ps.10bs), function(i) {
  tryCatch(
    par.fx(pars.fit.2ps.10bs[[i]], in.est[ix.10][[i]], verbose = FALSE, mod = "2ps", pass = FALSE),
    error = function (e) {cat("ERROR :", conditionMessage(e), "\n")})
})
names(Twops.10bs.fits) <- names(pars.fit.2ps.10bs)

## resp, bulk, stocks
# 0-10
Twops.10rbs.fits <- lapply(seq_along(pars.fit.2ps.10rbs), function(i) {
  tryCatch(
    par.fx(pars.fit.2ps.10rbs[[i]], in.est[ix.10][[i]], verbose = FALSE, mod = "2ps", pass = FALSE),
    error = function (e) {cat("ERROR :", conditionMessage(e), "\n")})
})
names(Twops.10rbs.fits) <- names(pars.fit.2ps.10rbs)
# 10-20
Twops.20rbs.fits <- lapply(seq_along(pars.fit.2ps.20rbs), function(i) {
  tryCatch(
    par.fx(pars.fit.2ps.20rbs[[i]], in.est[ix.20][[i]], verbose = FALSE, mod = "2ps", pass = FALSE),
    error = function (e) {cat("ERROR :", conditionMessage(e), "\n")})
})
names(Twops.20rbs.fits) <- names(pars.fit.2ps.20rbs)

# # remove null entries
# Twops.10b.fits <- Filter(Negate(is.null), Twops.10b.fits)
# Twops.30b.fits <- Filter(Negate(is.null), Twops.30b.fits)
# Twops.10br.fits <- Filter(Negate(is.null), Twops.10br.fits)
# Twops.30br.fits <- Filter(Negate(is.null), Twops.30br.fits)

# Look at role of resp constraint in fit
# lapply(seq_along(Twops.10b.fits), function(i) {
#   C14.2p.plot.fx(Twops.10b.fits[[i]],
#                  con.df = con.df.fx(names(Twops.10b.fits)[i]), 
#                  mod = "2ps bulk only",
#                  PMeco_depth = names(Twops.10b.fits)[i])
# })
lapply(seq_along(Twops.10br.fits), function(i) {
  C14.2p.plot.fx(Twops.10br.fits[[i]], 
                 con.df = con.df.fx(names(Twops.10br.fits)[i]), 
                 mod = "2ps bulk + resp",
                 PMeco_depth = names(Twops.10br.fits)[i])
})
# lapply(seq_along(Twops.10bs.fits), function(i) {
#   C14.2p.plot.fx(Twops.10bs.fits[[i]],
#                  con.df = con.df.fx(names(Twops.10bs.fits)[i]), 
#                  mod = "2ps bulk + stock",
#                  PMeco_depth = names(Twops.10bs.fits)[i])
# })
lapply(seq_along(Twops.10rbs.fits), function(i) {
  C14.2p.plot.fx(Twops.10rbs.fits[[i]], 
                 con.df = con.df.fx(names(Twops.10rbs.fits)[i]), 
                 mod = "bulk, resp, stock",
                 PMeco_depth = names(Twops.10rbs.fits)[i])
})
# 10-20
lapply(seq_along(Twops.20rbs.fits), function(i) {
  C14.2p.plot.fx(Twops.20rbs.fits[[i]], 
                 con.df = con.df.fx(names(Twops.20rbs.fits)[i]), 
                 mod = "bulk, resp, stock",
                 PMeco_depth = names(Twops.20rbs.fits)[i])
})
# lapply(seq_along(Twops.30b.fits), function(i) {
#   C14.2p.plot.fx(Twops.30b.fits[[i]],
#                  con.df = con.df.fx(names(Twops.30b.fits)[i]), 
#                  mod = "2ps bulk only",
#                  PMeco_depth = names(Twops.30b.fits)[i])
# })
# lapply(seq_along(Twops.30br.fits), function(i) {
#   C14.2p.plot.fx(Twops.30br.fits[[i]], 
#                  con.df = con.df.fx(names(Twops.30br.fits)[i]), 
#                  mod = "2ps bulk + resp",
#                  PMeco_depth = names(Twops.30br.fits)[i])
# })

## Show role of resp in constraining models
# GRwf 0-10
Twop.fit.plot.fx(Twops.10bs.fits[which(names(Twops.10bs.fits) == "GRwf_0-10")], 
                 "2ps 0-10cm, bulk 14c + stock", 
                 Twops.10rbs.fits[which(names(Twops.10rbs.fits) == "GRwf_0-10")],
                 "2ps 0-10cm, resp & bulk 14c + stock")
# BSrf 0-10
Twop.fit.plot.fx(Twops.10br.fits[which(names(Twops.10br.fits) == "BSrf_0-10")], 
                 "2ps 0-10cm w/ resp", 
                 Twops.10b.fits[which(names(Twops.10b.fits) == "BSrf_0-10")],
                 "2ps 0-10cm w/o resp")
Twop.fit.plot.fx(Twops.10rbs.fits[which(names(Twops.10rbs.fits) == "BSrf_0-10")],
                 "2ps 0-10cm w/ resp, bulk, stocks",
                 Twops.10bs.fits[which(names(Twops.10bs.fits) == "BSrf_0-10")],
                 "2ps 0-10cm w/o resp (bulk + stocks only)")
Twop.fit.plot.fx(Twops.10rbs.fits[which(names(Twops.10rbs.fits) == "BSwf_10-20")],
                 "Basalt/cool 10-20",
                 Twops.10rbs.fits[which(names(Twops.10rbs.fits) == "GRwf_10-20")],
                 "Granite/cool 10-20")

# compare resp + bulk fits w/ and w/o stocks
Twop.fit.plot.fx(Twops.10rbs.fits, 
                 "2ps 0-10cm w/ resp, bulk, stocks", 
                 Twops.10br.fits,
                 "2ps 0-10cm w/ resp + bulk, no stock")
# compare resp + bulk fits w/ and w/o stocks
Twop.fit.plot.fx(Twops.10bs.fits, 
                 "2ps 0-10cm, bulk 14c + stock", 
                 Twops.10rbs.fits,
                 "2ps 0-10cm, resp & bulk 14c + stock")
# compare BSwf and GRwf 10-20
BSGRwf20.con.df <- cbind(rbind(con.df.fx("BSwf_10-20"), con.df.fx("GRwf_10-20")),
                               pm = factor(rep(c("basalt", "granite"), each = c(11))))
BSGRwf20.con.df <- BSGRwf20.con.df[-which(BSGRwf20.con.df$Year == 2009.5), ]
ANGRwf20.con.df <- cbind(rbind(con.df.fx("BSwf_10-20"), con.df.fx("GRwf_10-20")),
                               pm = factor(rep(c("basalt", "granite"), each = c(11))))
BSGRwf20.con.df <- BSGRwf20.con.df[-which(BSGRwf20.con.df$Year == 2009.5), ]
atm.14c2 <- Twops.20rbs.fits$`BSwf_10-20`[Twops.20rbs.fits$`BSwf_10-20`$years >= 1950 & Twops.20rbs.fits$`BSwf_10-20`$pool == "atm", ]
# plot
p <- rbind(Twops.20rbs.fits$`BSwf_10-20`,
      Twops.20rbs.fits$`GRwf_10-20`) %>%
  mutate(pm = rep(c("basalt", "granite"), 
                  each = nrow(Twops.20rbs.fits$`BSwf_10-20`))) %>%
  filter(pool == "bulk C" | pool == "respiration") %>%
  ggplot(., aes(years, d14C)) +
  geom_path(data = atm.14c2) +
  geom_path(aes(linetype = pool, color = pm)) +
  geom_point(data = BSGRwf20.con.df, 
             aes(Year, d14c, color = pm, shape = pool), 
             size = 2.5,
             position = position_dodge(width = 1)) +
  scale_color_manual(
    name = "Parent material",
    values = c("basalt" = "red",
               "granite" = "darkgray")) +
  scale_shape_manual(
    name = "",
    values = c("bulk C" = 16,
               "respiration" = 1)) +
  scale_linetype_manual(
   name = "Pool",
   values = c("bulk C" = 1,
              "respiration" = 2)) +
  scale_x_continuous(limits = c(1950, 2022)) +
  xlab("Year") +
  ylab(expression(''*Delta*''^14*'C (‰)')) +
  theme_bw() +
  theme(panel.grid = element_blank())
ggsave("sra.2ps.BSGRwf20.pdf", p, dpi = 300, width = 6, height = 5, units = "in")
# compare resp + bulk fits w/ and w/o stocks
Twop.fit.plot.fx(Twops.20br.l.fits, 
                 "2ps 0-10cm, bulk 14c + stock", 
                 Twops.20rbs.fits,
                 "2ps 0-10cm, resp & bulk 14c + stock")
#####

# ages and transit times
#####
# 2ps
SA.2ps.20.rbs.ls <- lapply(seq_along(pars.fit.2ps.20rbs), function(i) {
  ks <- pars.fit.2ps.20rbs[[i]][1:2]
  tc <- pars.fit.2ps.20rbs[[i]][3]
  In <- in.est[ix.20][[i]]
  A <- diag(-ks)
  A[2, 1] <- tc * ks[1]
  return(systemAge(A = A, u = c(In, 0)))
})
names(SA.2ps.20.rbs.ls) <- names(pars.fit.2ps.20rbs)
lapply(SA.2ps.20.rbs.ls, "[[", 1)

## Transit time
# 2ps
TT.2ps.20.rbs.ls <- lapply(seq_along(pars.fit.2ps.20rbs), function(i) {
  ks <- pars.fit.2ps.20rbs[[i]][1:2]
  tc <- pars.fit.2ps.20rbs[[i]][3]
  In <- in.est[ix.20][[i]]
  A <- diag(-ks)
  A[2, 1] <- tc * ks[1]
  return(transitTime(A = A, u = c(In, 0)))
})
names(TT.2ps.20.rbs.ls) <- names(pars.fit.2ps.20rbs)
lapply(TT.2ps.20.rbs.ls, "[[", 1)
# 0-10
TT.MA.2ps.10.rbs.ls <- lapply(seq_along(pars.fit.2ps.10rbs), function(i) {
  ks <- pars.fit.2ps.10rbs[[i]][1:2]
  tc <- pars.fit.2ps.10rbs[[i]][3]
  In <- in.est[ix.10][[i]]
  A <- diag(-ks)
  A[2, 1] <- tc * ks[1]
  TT <- transitTime(A = A, u = c(In, 0))
  Age <- systemAge(A = A, u = c(In, 0))
  return(list(TT = TT$meanTransitTime, Age = Age$meanSystemAge))
})
names(TT.MA.2ps.10.rbs.ls) <- names(pars.fit.2ps.10rbs)
lapply(TT.MA.2ps.10.rbs.ls, unlist)
# 
ageD.2ps.10.rbs.ls <- lapply(seq_along(pars.fit.2ps.10rbs), function(i) {
  ks <- pars.fit.2ps.10rbs[[i]][1:2]
  tc <- pars.fit.2ps.10rbs[[i]][3]
  In <- in.est[ix.10][[i]]
  A <- diag(-ks)
  A[2, 1] <- tc * ks[1]
  return(systemAge(A = A, u = c(In, 0)))
})
names(ageD.2ps.10.rbs.ls) <- names(pars.fit.2ps.10rbs)
# compare output of 2pp and 2ps model fits
merge(ssr.2pp.df, ssr.2ps.df, by = "PMeco_depth", suffixes = c("_2pp", "_2ps")) %>%
  mutate(ssr_2pp = round(ssr_2pp, 1),
         ssr_2ps = round(ssr_2ps, 1),
         dif = ssr_2pp - ssr_2ps)
merge(var_ms.2pp.df,
      var_ms.2ps.df,
      by = c("PMeco_depth", "var"),
      suffixes = c("_2pp", "_2ps")) %>%
  mutate(var_ms_2pp = round(var_ms_2pp, 4),
         var_ms_2ps = round(var_ms_2ps, 4),
         dif = var_ms_2pp - var_ms_2ps)

## Plot
# SSR, PM
rbind(ssr.2pp.df, ssr.2ps.df) %>%
  mutate(mod = rep(c("2pp", "2ps"), each = nrow(ssr.2pp.df)),
         PM = substr(PMeco_depth, 1, 2),
         eco = substr(PMeco_depth, 3, 4)) %>%
  group_by(PM, mod) %>%
  summarize(mean.ssr = mean(ssr), sd = sd(ssr)) %>%
  mutate(err_u = mean.ssr + sd/sqrt(3),
         err_l = mean.ssr - sd/sqrt(3)) %>%
  ggplot(., aes(mod, mean.ssr, fill = PM)) +
  geom_col(position = "dodge") +
  geom_errorbar(
    aes(ymax = err_u, ymin = err_l), 
    position = position_dodge(width = .9),
    width = .3) +
  scale_fill_manual(name = "Parent material",
                    labels = c("AN" = "andesite",
                               "BS" = "basalt",
                               "GR" = "granite"),
                    values = c("AN" = "blue", 
                               "BS" = "red", 
                               "GR" = "darkgray")) +
  facet_wrap(. ~ PM) +
  ggtitle("SSR 2-pool models 0-10 cm") +
  theme_bw() +
  theme(panel.grid.minor = element_blank())
# SSR, eco
rbind(ssr.2pp.df, ssr.2ps.df) %>%
  mutate(mod = rep(c("2pp", "2ps"), each = nrow(ssr.2pp.df)),
         PM = substr(PMeco_depth, 1, 2),
         eco = substr(PMeco_depth, 3, 4)) %>%
  group_by(eco, mod) %>%
  summarize(mean.ssr = mean(ssr), sd = sd(ssr)) %>%
  mutate(err_u = mean.ssr + sd/sqrt(3),
         err_l = mean.ssr - sd/sqrt(3)) %>%
  ggplot(., aes(mod, mean.ssr, fill = eco)) +
  geom_col(position = "dodge") +
  geom_errorbar(
    aes(ymax = err_u, ymin = err_l), 
    position = position_dodge(width = .9),
    width = .3) +
  facet_wrap(. ~ eco) +
  ggtitle("SSR 2-pool models 0-10 cm (eco)") +
  theme_bw() +
  theme(panel.grid.minor = element_blank())

# var_ms, PM
rbind(var_ms.2pp.df, var_ms.2ps.df) %>%
  mutate(mod = rep(c("2pp", "2ps"), each = nrow(var_ms.2pp.df)),
         PM = substr(PMeco_depth, 1, 2),
         eco = substr(PMeco_depth, 3, 4)) %>%
  group_by(var, PM, mod) %>%
  summarize(mean.var_ms = mean(var_ms), sd = sd(var_ms)) %>%
  mutate(err_u = mean.var_ms + sd/sqrt(3),
         err_l = mean.var_ms - sd/sqrt(3)) %>%
  ggplot(., aes(mod, mean.var_ms, fill = PM)) +
  geom_col(position = "dodge") +
  geom_errorbar(
    aes(ymax = err_u, ymin = err_l), 
    position = position_dodge(width = .9),
    width = .3) +
  scale_fill_manual(name = "Parent material",
                    labels = c("AN" = "andesite",
                               "BS" = "basalt",
                               "GR" = "granite"),
                    values = c("AN" = "blue", 
                               "BS" = "red", 
                               "GR" = "darkgray")) +
  facet_wrap(. ~ var, scales = "free") +
  ggtitle("Residual error 2-pool models 0-10 cm") +
  theme_bw() +
  theme(panel.grid.minor = element_blank())
# var_ms, eco
rbind(var_ms.2pp.df, var_ms.2ps.df) %>%
  mutate(mod = rep(c("2pp", "2ps"), each = nrow(var_ms.2pp.df)),
         PM = substr(PMeco_depth, 1, 2),
         eco = substr(PMeco_depth, 3, 4)) %>%
  group_by(var, eco, mod) %>%
  summarize(mean.var_ms = mean(var_ms), sd = sd(var_ms)) %>%
  mutate(err_u = mean.var_ms + sd/sqrt(3),
         err_l = mean.var_ms - sd/sqrt(3)) %>%
  ggplot(., aes(mod, mean.var_ms, fill = eco)) +
  geom_col(position = "dodge") +
  geom_errorbar(
    aes(ymax = err_u, ymin = err_l), 
    position = position_dodge(width = .9),
    width = .3) +
  facet_wrap(. ~ var, scales = "free") +
  ggtitle("Residual error 2-pool models 0-10 cm") +
  theme_bw() +
  theme(panel.grid.minor = element_blank())
## System age
# 2pp
SA.2pp.ls <- lapply(seq_along(pars.fit.2pp), function(i) {
  ks <- pars.fit.2pp[[i]][1:2]
  gam <- pars.fit.2pp[[i]][3]
  In <- in.fit.2pp[[i]]
  return(systemAge(, u = In))
})
names(SA.2pp.ls) <- names(pars.fit.2pp)
# 2pp gam = [.5, .95]
SA.2pp.p3.5.95.ls <- lapply(seq_along(pars.fit.2pp.p3.5.95), function(i) {
  ks <- pars.fit.2pp.p3.5.95[[i]][1:2]
  gam <- pars.fit.2pp.p3.5.95[[i]][3]
  In <- in.fit.2pp.p3.5.95[[i]]
  return(systemAge(A = -1 * diag(ks), u = c(In * gam, In * (1 - gam))))
})
names(SA.2pp.p3.5.95.ls) <- names(pars.fit.2pp.p3.5.95)
# 2ps
SA.2ps.ls <- lapply(seq_along(pars.fit.2ps), function(i) {
  ks <- pars.fit.2ps[[i]][1:2]
  gam <- pars.fit.2ps[[i]][3]
  In <- in.fit.2ps[[i]]
  return(systemAge(A = -1 * diag(ks), u = c(In * gam, In * (1 - gam))))
})
names(SA.2ps.ls) <- names(pars.fit.2ps)

## Transit time
# 2pp
TT.2pp.ls <- lapply(seq_along(pars.fit.2pp), function(i) {
  ks <- pars.fit.2pp[[i]][1:2]
  gam <- pars.fit.2pp[[i]][3]
  In <- in.fit.2pp[[i]]
  return(transitTime(A = -1 * diag(ks), u = c(In * gam, In * (1 - gam))))
})
names(TT.2pp.ls) <- names(pars.fit.2pp)
# 2pp gam = [.5, .95]
TT.2pp.p3.5.95.ls <- lapply(seq_along(pars.fit.2pp.p3.5.95), function(i) {
  ks <- pars.fit.2pp.p3.5.95[[i]][1:2]
  gam <- pars.fit.2pp.p3.5.95[[i]][3]
  In <- in.fit.2pp.p3.5.95[[i]]
  return(transitTime(A = -1 * diag(ks), u = c(In * gam, In * (1 - gam))))
})
names(TT.2pp.p3.5.95.ls) <- names(pars.fit.2pp.p3.5.95)
# 2ps
TT.2ps.ls <- lapply(seq_along(pars.fit.2ps), function(i) {
  ks <- pars.fit.2ps[[i]][1:2]
  gam <- pars.fit.2ps[[i]][3]
  In <- in.fit.2ps[[i]]
  return(transitTime(A = -1 * diag(ks), u = c(In * gam, In * (1 - gam))))
})
names(TT.2ps.ls) <- names(pars.fit.2ps)
# compare ages and transit times among the two model structures
SA.2p.ls <- list(SA.2pp.ls, SA.2ps.ls, SA.2pp.p3.5.95.ls)
SA.df <- bind_rows(
  lapply(SA.2p.ls, function(ls) {
    lapply(seq_along(ls), function(i) {
      data.frame(age = c(ls[[i]][["meanSystemAge"]],
                         ls[[i]][["meanPoolAge"]]),
                 component = c("system", "fast pool", "slow pool"))
    })
  })
)
SA.df$PMeco_depth <- rep(names(SA.2pp.ls), each = 3, times = length(SA.2p.ls))
SA.df$Model <- rep(c("2pp", "2ps", "2pp [.5, .95]"), each = 27)
TT.2p.ls <- list(TT.2pp.ls, TT.2ps.ls, TT.2pp.p3.5.95.ls)
TT.df <- bind_rows(
  lapply(TT.2p.ls, function(ls) {
    lapply(seq_along(ls), function(i) {
     data.frame(age = ls[[i]][["meanTransitTime"]],
                component = "transit")
    })
  })
)
TT.df$PMeco_depth <- rep(names(TT.2pp.ls), times = length(TT.2p.ls))
TT.df$Model <- rep(c("2pp", "2ps", "2pp [.5, .95]"), each = 9)
SA.TT.df <- rbind(SA.df, TT.df)
SA.TT.df$PM <- substr(SA.TT.df$PMeco_depth, start = 1, stop = 2)
SA.TT.df$eco <- substr(SA.TT.df$PMeco_depth, start = 3, stop = 4)

## Plot ages and transit times
# by PM
SA.TT.df %>%
  select(!c(PMeco_depth, eco)) %>%
  group_by(component, PM, Model) %>%
  summarize_all(list(mean_age = mean, sd = sd)) %>%
  mutate(err_u = mean_age + sd,
         err_l = mean_age - sd) %>%
  ggplot(., aes(Model, mean_age, fill = PM)) +
  geom_col(position = "dodge") +
  # geom_errorbar(
  #   aes(ymax = err_u, ymin = err_l), 
  #   position = position_dodge(width = .9),
  #   width = .3) +
  scale_fill_manual(name = "Parent material",
                    labels = c("AN" = "andesite",
                               "BS" = "basalt",
                               "GR" = "granite"),
                    values = c("AN" = "blue", 
                               "BS" = "red", 
                               "GR" = "darkgray")) +
  facet_wrap(. ~ component, scales = "free") +
  ylab("mean age") +
  theme_bw() +
  theme(panel.grid.minor = element_blank())
# by eco
SA.TT.df %>%
  select(!c(PMeco_depth, PM)) %>%
  group_by(component, eco, Model) %>%
  summarize_all(list(mean_age = mean, sd = sd)) %>%
  mutate(err_u = mean_age + sd,
         err_l = mean_age - sd) %>%
  ggplot(., aes(Model, mean_age, fill = eco)) +
  geom_col(position = "dodge") +
  # geom_errorbar(
  #   aes(ymax = err_u, ymin = err_l),
  #   position = position_dodge(width = .9),
  #   width = .3) +
  facet_wrap(. ~ component, scales = "free") +
  ylab("mean age") +
  theme_bw() +
  theme(panel.grid.minor = element_blank())

Bayesian parameter estimation (MCMC)

# the following .RData files are generated by script "sra-ts/source/sra-ts-14c-mcmc-bayes.R"
load(file = "../data/derived/bayes-par-fit-2020-11-06/bayes_fit_2pp_0-10_5000iter.RData")
load(file = "../data/derived/bayes-par-fit-2020-11-17/bayes_fit_2ps_0-10_5000iter.RData")

# # plot parameter convergence
# lapply(bayes_fit_2pp_0_10, plot)
# lapply(bayes_fit_2ps_0_10, plot)

# plot collinearity
iter <- 5000
lapply(bayes_fit_2pp_0_10, pairs, nsample = floor(iter/4))
lapply(bayes_fit_2ps_0_10, pairs, nsample = floor(iter/4))

## look at model performance
pars.bayes.df.fx <- function(mod, pars.bayes, pars.fit) {
  bind_rows(lapply(seq_along(pars.bayes), function(i) {
    ix <- match(unique(pars.bayes[[i]][["pars"]][, 1]), pars.bayes[[i]][["pars"]][, 1])
    df <- data.frame(k1 = pars.bayes[[i]][["pars"]][ix, 1],
                     k2 = pars.bayes[[i]][["pars"]][ix, 2],
                     p3 = pars.bayes[[i]][["pars"]][ix, 3])
    df <- cbind(df,
                PMeco_depth = rep(names(pars.fit)[i], length(ix)),
                mod = rep(mod, length(ix)))
    df <- cbind(df, 
                PM = factor(substr(df$PMeco_depth, 1, 2)),
                eco = factor(substr(df$PMeco_depth, 3, 4), levels = c("pp", "wf", "rf")))
    return(df)
  }))
}
pars.bayes.2pp.df <- pars.bayes.df.fx("2pp", bayes_fit_2pp_0_10, pars.fit.2pp)
pars.bayes.2ps.df <- pars.bayes.df.fx("2ps", bayes_fit_2ps_0_10, pars.fit.2ps)

# # linear fits
# summary(lm(k2 ~ PM, pars.bayes.2pp.df))
# summary(lm(k2 ~ eco, pars.bayes.2pp.df))
# summary(lm(k1 ~ PM, pars.bayes.2pp.df))
# summary(lm(k1 ~ eco, pars.bayes.2pp.df))
# summary(lm(p3 ~ PM, pars.bayes.2pp.df))
# summary(lm(p3 ~ eco, pars.bayes.2pp.df))

# best par set
bestPars.bayes.ls <- lapply(bayes_fit_2pp_0_10, function(x) {
  round(data.frame(k1 = x$bestpar[1],
                   k2 = x$bestpar[2],
                   gam = x$bestpar[3]),
        4)
})
bestPars.bayes.df <- cbind(PM = rep(c("AN", "BS", "GR"), each = 3),
                           eco = rep(c("pp", "rf", "wf"), 3),
                           depth = rep("0-10", 9),
                           bind_rows(bestPars.bayes.ls))

# summarize by PM
pars.bayes.PM <- bestPars.bayes.df %>%
  select(!c(eco, depth)) %>%
  group_by(PM) %>%
  summarize_all(list(mean = mean, sd = sd)) %>%
  mutate_if(is.numeric, format, digits = 3)
# summarize by ECO
pars.bayes.eco <- bestPars.bayes.df %>%
  select(!c(PM, depth)) %>%
  group_by(eco) %>%
  summarize_all(list(mean = mean, sd = sd)) %>%
  mutate_if(is.numeric, format, digits = 3)

# plot best pars
bestPars.bayes.df %>%
  pivot_longer(!(PM:depth), names_to = "par", values_to = "value") %>%
  mutate(PM = factor(PM),
         eco = factor(eco, levels = c("pp", "wf", "rf"))) %>%
  ggplot(., aes(par, value, color = PM, shape = eco)) +
  geom_jitter(size = 4) +
  scale_color_manual(name = "parent material",
                    labels = c("AN" = "andesite",
                               "BS" = "basalt",
                               "GR" = "granite"),
                    values = c("AN" = "blue", 
                               "BS" = "red", 
                               "GR" = "darkgray")) +
  facet_wrap(. ~ par, scales = "free") +
  theme_bw() +
  theme(panel.grid.minor = element_blank())

# plot accepted pars by PM and then by eco
pars.bayes.df %>%
  pivot_longer(!c(PM, eco, PMeco_depth), names_to = "par", values_to = "value") %>%
  mutate(PM = factor(PM),
         eco = factor(eco, levels = c("pp", "wf", "rf"))) %>%
  ggplot(., aes(par, value, fill = PM)) +
  geom_boxplot() +
  scale_fill_manual(name = "parent material",
                    labels = c("AN" = "andesite",
                               "BS" = "basalt",
                               "GR" = "granite"),
                    values = c("AN" = "blue", 
                               "BS" = "red", 
                               "GR" = "darkgray")) +
  facet_wrap(. ~ par, scales = "free") +
  theme_bw() +
  theme(panel.grid.minor = element_blank())
pars.bayes.df %>%
  pivot_longer(!c(PM, eco, PMeco_depth), names_to = "par", values_to = "value") %>%
  mutate(PM = factor(PM),
         eco = factor(eco, levels = c("pp", "wf", "rf"))) %>%
  ggplot(., aes(par, value, fill = eco)) +
  geom_boxplot() +
  facet_wrap(. ~ par, scales = "free") +
  theme_bw() +
  theme(panel.grid.minor = element_blank())
LS0tCnRpdGxlOiAiU2llcnJhIE5ldmFkYSBUaW1lIFNlcmllcyIKYXV0aG9yOiAiSi4gQmVlbS1NaWxsZXIiCmRhdGU6ICIyMSBPY3QgMjAyMCIKb3V0cHV0OgogIHBkZl9kb2N1bWVudDoKICAgIGxhdGV4X2VuZ2luZTogeGVsYXRleAogIGh0bWxfbm90ZWJvb2s6CiAgICB0b2M6IHllcwogICAgdG9jX2RlcHRoOiAyCiAgICBjc3M6IGN1c3RvbS5jc3MKaGVhZGVyX2luY2x1ZGVzOgogIC0gXHVzZXBhY2thZ2VbdXRmOF17aW5wdXRlbmN9CiAgLSBcdXNlcGFja2FnZXtmbG9hdH0KLS0tCmBgYHtyIGdsb2JhbF9vcHRpb25zLCBpbmNsdWRlID0gRkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gRkFMU0UsIHdhcm5pbmcgPSBGQUxTRSwgbWVzc2FnZSA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgZmlnLmFsaWduID0gJ2NlbnRlcicsIGRldiA9ICdjYWlyb19wZGYnKQpgYGAKCmBgYHtyIHNldHVwLCBpbmNsdWRlID0gRkFMU0V9CmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShkcGx5cikKIyBzdXBwcmVzcyBncm91cGluZyBpbmZvcm1hdGlvbiBtZXNzYWdlCm9wdGlvbnMoZHBseXIuc3VtbWFyaXNlLmluZm9ybSA9IEZBTFNFKQpsaWJyYXJ5KElTUmFEKQpsaWJyYXJ5KEdTSUYpCmxpYnJhcnkoYXFwKQpsaWJyYXJ5KFNvaWxSKQpsaWJyYXJ5KEZNRSkKbGlicmFyeSh0aWR5cikKbGlicmFyeShyZWFkeGwpCmxpYnJhcnkoZ3QpCmxpYnJhcnkocHVycnIpCmBgYAoKIyBEYXRhIHByZXBhcmF0aW9uIHNjcmlwdCBmb3IgU2llcnJhIE5ldmFkYSB0aW1lIHNlcmllcyBhbmFseXNpcwoKYGBge3IgbG9hZCBhbXMtamVuYS1pbmdlc3QgZnh9CiMgMS4gUmVhZCBpbiBpc290b3BlIGRhdGEgZnJvbSB2YXJpb3VzIHNvdXJjZXMKIyBGaXJzdCBsb2FkIGhlbHBlciBmdW5jdGlvbnMgJ3JlYWRfamVuYV9hbXNfcmVzdWx0cy5SJywgJ3JlYWRfamVuYV9pc29fcmVzdWx0cy5SJyAKc291cmNlKCIuL3V0aWxpdGllcy9qZW5hX2Ftc19pbmdlc3QuUiIpCnNvdXJjZSgiLi91dGlsaXRpZXMvamVuYV9pc29faW5nZXN0LlIiKQpzb3VyY2UoIi4vdXRpbGl0aWVzL2plbmFfZWxtX2luZ2VzdC5SIikKYGBgCgpgYGB7ciBwbG90LWZ1bnN9CiMgY29sb3IgcGFsZXR0ZXMgZm9yIEVDTyAmIFBNCndhcm0gPC0gIiNCRjgxMkQiCmNvb2wgPC0gIiM4MENEQzEiCmNvbGQgPC0gIiMwMTY2NUUiCmdyYW5pdGUgPC0gIiM5ZGFiYTkiCmFuZGVzaXRlIDwtICIjMzgyZGJmIgpiYXNhbHQgPC0gIiNiZjM4MmQiCmBgYAoKYGBge3IgcmVhZC1jbi1pc28tZGF0YSwgaW5jbHVkZSA9IEZBTFNFfQojIDIuIE5leHQgcmVhZCBpbiBkYXRhIGZyb20gdGhlIGFwcHJvcHJpYXRlIGRpcmVjdG9yaWVzIGluICdkYXRhL3JhdycKIyAxNEMKIyBpZGVudGlmeSBzdWJkaXJlY3RvcmllcyBpbiAncmF3JyBkaXJlY3Rvcnkgd2l0aCAiYW1zX2plbmEiIGluIG5hbWUKYW1zX2plbmFfcmVzdWx0c19kaXJzIDwtIGxpc3QuZmlsZXMoIi4uL2RhdGEvcmF3IiwgcGF0dGVybiA9ICJhbXNfamVuYV9yZXN1bHRzIiwgZnVsbC5uYW1lcyA9IFRSVUUpCmFtc19yZXN1bHRzX2xzIDwtIGxhcHBseShzZXFfYWxvbmcoYW1zX2plbmFfcmVzdWx0c19kaXJzKSwgZnVuY3Rpb24oaSkgewogIHJlYWRfamVuYV9hbXNfcmVzdWx0cyhhbXNfamVuYV9yZXN1bHRzX2RpcnNbaV0pCn0pCm5hbWVzKGFtc19yZXN1bHRzX2xzKSA8LSBsaXN0LmZpbGVzKCIuLi9kYXRhL3JhdyIsIHBhdHRlcm4gPSAiYW1zX2plbmFfcmVzdWx0cyIpCgojICMgMTNDCiMgIyBpZGVudGlmeSBzdWJkaXJlY3RvcmllcyBpbiAncmF3JyBkaXJlY3Rvcnkgd2l0aCAiaXNvX2plbmEiIGluIG5hbWUKIyBpc29famVuYV9yZXN1bHRzX2RpcnMgPC0gbGlzdC5maWxlcygiLi4vZGF0YS9yYXciLCBwYXR0ZXJuID0gImlzb19qZW5hX3Jlc3VsdHMiLCBmdWxsLm5hbWVzID0gVFJVRSkKIyBpc29fcmVzdWx0c19scyA8LSBsYXBwbHkoc2VxX2Fsb25nKGlzb19qZW5hX3Jlc3VsdHNfZGlycyksIGZ1bmN0aW9uKGkpIHsKIyAgIHJlYWRfamVuYV9pc29fcmVzdWx0cyhpc29famVuYV9yZXN1bHRzX2RpcnNbaV0pCiMgfSkKIyBuYW1lcyhpc29fcmVzdWx0c19scykgPC0gbGlzdC5maWxlcygiLi4vZGF0YS9yYXciLCBwYXR0ZXJuID0gImlzb19qZW5hX3Jlc3VsdHMiKQoKIyBSZWFkIGluIEMgYW5kIE4gZGF0YQplbG1fcmVzdWx0c19kaXIgPC0gbGlzdC5maWxlcygiLi4vZGF0YS9yYXciLCBwYXR0ZXJuID0gImVsbV9qZW5hX3Jlc3VsdHMiLCBmdWxsLm5hbWVzID0gVFJVRSkKZWxtX3Jlc3VsdHNfbHMgPC0gbGFwcGx5KHNlcV9hbG9uZyhlbG1fcmVzdWx0c19kaXIpLCBmdW5jdGlvbihpKSB7CiAgcmVhZF9qZW5hX2VsbV9yZXN1bHRzKGVsbV9yZXN1bHRzX2RpcltpXSkKfSkKbmFtZXMoZWxtX3Jlc3VsdHNfbHMpIDwtIGxpc3QuZmlsZXMoIi4uL2RhdGEvcmF3IiwgcGF0dGVybiA9ICJlbG1famVuYV9yZXN1bHRzIikKYGBgCgpgYGB7ciBkYXRhLXRlbXBsYXRlfQojIENyZWF0ZSB0ZW1wbGF0ZSBmb3IgYnVsayBzb2lsIGRhdGEKdGVtcGxhdGUxOS5meCA8LSBmdW5jdGlvbihwbSwgZWNvLCBuZGVwdGgpIHsKICBkZiA8LSBkYXRhLmZyYW1lKFllYXIgPSByZXAoMjAxOSwgbmRlcHRoICogMyksCiAgICAgICAgICAgICAgICAgICBQTSA9IHJlcChwbSwgbmRlcHRoICogMyksCiAgICAgICAgICAgICAgICAgICBFQ08gPSByZXAoZWNvLCBuZGVwdGggKiAzKSwKICAgICAgICAgICAgICAgICAgIHByb19yZXAgPSByZXAoc2VxKDEsMyksIGVhY2ggPSBuZGVwdGgpLAogICAgICAgICAgICAgICAgICAgbHlyX3RvcCA9IHJlcChzZXEoMCwgKG5kZXB0aC0xKSAqIDEwLCBieSA9IDEwKSwgMyksCiAgICAgICAgICAgICAgICAgICBseXJfYm90ID0gcmVwKHNlcSgxMCwgKG5kZXB0aCkgKiAxMCwgYnkgPSAxMCksIDMpKQogIGRmJHByb19uYW1lIDwtIHBhc3RlMChkZiRQTSwgZGYkRUNPLCAiXyIsIGRmJHByb19yZXApCiAgZGYkbHlyX25hbWUgPC0gcGFzdGUwKGRmJHByb19uYW1lLCAiXyIsIGRmJGx5cl90b3AsICItIiwgZGYkbHlyX2JvdCkKICByZXR1cm4oZGYpCn0KCiMgQ3JlYXRlIHRlbXBsYXRlIGZvciBjb21wb3NpdGUgc29pbCBkYXRhIChpbmN1YmF0aW9ucywgZGVuc2l0eSBmcmFjdGlvbnMsIGV0Yy4pCnRlbXBsYXRlLmNvbXAuZnggPC0gZnVuY3Rpb24oeWVhciwgcG0sIGVjbywgZGVwdGhfYm90ID0gYygxMCwgMjAsIDMwKSwgZGF0KSB7CiAgbmRlcHRoIDwtIGxlbmd0aChkZXB0aF9ib3QpCiAgZGYgPC0gZGF0YS5mcmFtZShZZWFyID0gcmVwKHllYXIsIG5kZXB0aCAqIGxlbmd0aChwbSkpLAogICAgICAgICAgICAgICAgICAgUE0gPSByZXAocG0sIGVhY2ggPSBuZGVwdGggKiBsZW5ndGgoZWNvKSksCiAgICAgICAgICAgICAgICAgICBFQ08gPSByZXAoZWNvLCBlYWNoID0gbmRlcHRoKSkKICBkZiRseXJfYm90IDwtIGRlcHRoX2JvdAogIGRmJGx5cl90b3AgPC0gc2FwcGx5KHNlcV9hbG9uZyhkZXB0aF9ib3QpLCBmdW5jdGlvbihpKSB7CiAgICBpZiAoaSA9PSAxKSB7CiAgICAgIGRlcHRoX3RvcCA8LSAwCiAgICAgIH0gZWxzZSB7CiAgICAgICAgZGVwdGhfdG9wIDwtIGRlcHRoX2JvdFtpIC0gMV0KICAgICAgfQogIH0pCiAgZGYkcHJvX25hbWUgPC0gcGFzdGUwKGRmJFBNLCBkZiRFQ08sICJfY29tcCIpCiAgbiA8LSBucm93KGRmKQogIGlmIChkYXQgPT0gImluYyIpIHsKICAgIGRmIDwtIHJiaW5kKGRmLCBkZikKICAgIGRmJHJlcCA8LSByZXAoYygiYSIsICJiIiksIGVhY2ggPSBuKQogICAgZGYkbHlyX25hbWUgPC0gcGFzdGUwKGRmJHByb19uYW1lLCAiXyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgIGRmJGx5cl90b3AsICItIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgZGYkbHlyX2JvdCwgIl8iLCAKICAgICAgICAgICAgICAgICAgICAgICAgICBkZiRZZWFyLCAiXyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgZGYkcmVwKQogIH0gZWxzZSBpZiAoZGF0ID09ICJkZW5zaXR5IikgewogICAgZGYgPC0gcmJpbmQoZGYsIGRmLCBkZikKICAgIGRmJGZyYyA8LSByZXAoYygiZkxGIiwgIm9MRiIsICJtbkMiKSwgZWFjaCA9IG4pCiAgICBkZiRseXJfbmFtZSA8LSBwYXN0ZTAoZGYkcHJvX25hbWUsICJfIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgZGYkbHlyX3RvcCwgIi0iLCAKICAgICAgICAgICAgICAgICAgICAgICAgICBkZiRseXJfYm90LCAiXyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgIGRmJFllYXIsICJfIiwKICAgICAgICAgICAgICAgICAgICAgICAgICBkZiRmcmMpCiAgfQogIHJldHVybihkZikKfQoKIyB0ZW1wbGF0ZXMgZm9yIGJ1bGsgc29pbCBkYXRhCiMgR1JyZiAKR1JyZiA8LSB0ZW1wbGF0ZTE5LmZ4KCJHUiIsICJyZiIsIDcpCkdScmYgPC0gaWYoYW55KEdScmYkbHlyX25hbWUgPT0gIkdScmZfMV82MF83MCIpKSB7CiAgR1JyZiA8LSBHUnJmWy13aGljaChHUnJmJGx5cl9uYW1lID09ICJHUnJmXzFfNjBfNzAiKSwgXSAjIE5COiBHUnJmXzFfNjBfNzAgZG9lc24ndCBleGlzdAp9IGVsc2UgewogIEdScmYgPC0gR1JyZgp9CiMgR1J3ZgpHUndmIDwtIHRlbXBsYXRlMTkuZngoIkdSIiwgIndmIiwgOSkKIyBHUnBwCkdScHAgPC0gdGVtcGxhdGUxOS5meCgiR1IiLCAicHAiLCA4KQoKIyBBTnJmIApBTnJmIDwtIHRlbXBsYXRlMTkuZngoIkFOIiwgInJmIiwgNikKIyBBTndmCkFOd2YgPC0gdGVtcGxhdGUxOS5meCgiQU4iLCAid2YiLCA2KQojIEFOcHAKQU5wcCA8LSB0ZW1wbGF0ZTE5LmZ4KCJBTiIsICJwcCIsIDgpCgojIEJTcmYgCkJTcmYgPC0gdGVtcGxhdGUxOS5meCgiQlMiLCAicmYiLCA4KQpCU3JmIDwtIGlmKGFueShCU3JmJGx5cl9uYW1lID09ICJHUnJmXzFfNjBfNzAiKSkgewogIEJTcmYgPC0gQlNyZlstd2hpY2goQlNyZiRseXJfbmFtZSA9PSAiQlNyZl8xXzcwXzgwIiksIF0gIyBOQjogQlNyZl8xXzcwXzgwIGRvZXNuJ3QgZXhpc3QKfSBlbHNlIHsKICBCU3JmIDwtIEJTcmYKfSAKIyBCU3dmCkJTd2YgPC0gdGVtcGxhdGUxOS5meCgiQlMiLCAid2YiLCA3KQojIEJTcHAKQlNwcCA8LSB0ZW1wbGF0ZTE5LmZ4KCJCUyIsICJwcCIsIDgpCkJTcHBbQlNwcCRseXJfYm90ID09IDgwLCAibHlyX2JvdCJdIDwtIDc1ICMgb25seSBzYW1wbGVkIHRvIDc1Y20sIG5vdCA4MAoKc3JhLjIwMTkuZGYgPC0gcmJpbmQoR1JyZiwgR1J3ZiwgR1JwcCwKICAgICAgICAgICAgICAgICAgICAgQU5yZiwgQU53ZiwgQU5wcCwKICAgICAgICAgICAgICAgICAgICAgQlNyZiwgQlN3ZiwgQlNwcCkKCiMgdGVtcGxhdGUgZm9yIDIwMTkgaW5jdWJhdGlvbiBkYXRhCnNyYS4yMDE5LmluYy5kZiA8LSB0ZW1wbGF0ZS5jb21wLmZ4KDIwMTksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwbSA9IGMoIkFOIiwgIkJTIiwgIkdSIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVjbyA9IGMoInBwIiwgIndmIiwgInJmIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdCA9ICJpbmMiKQoKIyMgdGVtcGxhdGUgZm9yIDIwMDEgaW5jdWJhdGlvbiBkYXRhCiMgbGlzdCBvZiBkZXB0aHMgZm9yIDIwMDEgaW5jIHNhbXBsZXMKZGVwdGhfYm90XzIwMDEubHMgPC0gbGlzdChBTnBwID0gYyg2LCAxMywgMzMpLAogICAgICAgICAgICAgICAgICAgICAgICAgIEFOd2YgPSBjKDExLCAzNSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgQU5yZiA9IGMoMTEsIDMyKSwKICAgICAgICAgICAgICAgICAgICAgICAgICBCU3BwID0gYyg3LCAxOCwgMjgpLAogICAgICAgICAgICAgICAgICAgICAgICAgIEJTd2YgPSBjKDEwLCAxOSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgQlNyZiA9IGMoOCwgMTUsIDMwKSwKICAgICAgICAgICAgICAgICAgICAgICAgICBHUnBwID0gYyg3LCAxNSwgMjcpLAogICAgICAgICAgICAgICAgICAgICAgICAgIEdSd2YgPSBjKDQsIDEzLCAyOCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgR1JyZiA9IGMoOCwgMjcpKSAKIyB0ZW1wbGF0ZSBmb3IgaW5wdXRzIHRvIHRlbXBsYXRlLmNvbXAuZnggKHllYXIsIHBtLCBlY28pCmluYy4yMDAxLnRlbXBsYXRlIDwtIGxhcHBseShzZXFfYWxvbmcoZGVwdGhfYm90XzIwMDEubHMpLCBmdW5jdGlvbihpKSB7CiAgbm1zIDwtIG5hbWVzKGRlcHRoX2JvdF8yMDAxLmxzKQogIGxzIDwtIGxpc3QoeWVhciA9IDIwMDEsIAogICAgICAgICAgICAgcG0gPSBzdWJzdHIobm1zW2ldLCAxLCAyKSwgCiAgICAgICAgICAgICBlY28gPSBzdWJzdHIobm1zW2ldLCAzLCA0KSkKICBscyRkZXB0aF9ib3QgPC0gZGVwdGhfYm90XzIwMDEubHNbW2ldXQogIHJldHVybihscykKfSkKIyBjcmVhdGUgdGVtcGxhdGUgZGF0YSBmcmFtZSBieSBpdGVyYXRpdmVseSBjYWxsaW5nIHRlbXBsYXRlLmNvbXAuZngKc3JhLjIwMDEuaW5jLmRmIDwtIGJpbmRfcm93cygKICBsYXBwbHkoc2VxX2Fsb25nKGluYy4yMDAxLnRlbXBsYXRlKSwgZnVuY3Rpb24oaSkgewogICAgdGVtcGxhdGUuY29tcC5meCh5ZWFyID0gaW5jLjIwMDEudGVtcGxhdGVbW2ldXVtbMV1dLAogICAgICAgICAgICAgICAgICAgICBwbSA9IGluYy4yMDAxLnRlbXBsYXRlW1tpXV1bWzJdXSwKICAgICAgICAgICAgICAgICAgICAgZWNvID0gaW5jLjIwMDEudGVtcGxhdGVbW2ldXVtbM11dLAogICAgICAgICAgICAgICAgICAgICBkZXB0aF9ib3QgPSBpbmMuMjAwMS50ZW1wbGF0ZVtbaV1dW1s0XV0sCiAgICAgICAgICAgICAgICAgICAgIGRhdCA9ICJpbmMiKQogIH0pCikKCiMgMjAwMSBidWxrIHNvaWwgdGVtcGxhdGUKc3JhLjIwMDEgPC0gdmVjdG9yKG1vZGUgPSAibGlzdCIsIGxlbmd0aCA9IGxlbmd0aCh1bmlxdWUoc3JhLjIwMTkuZGYkcHJvX25hbWUpKSkKbmFtZXMoc3JhLjIwMDEpIDwtIHVuaXF1ZShzcmEuMjAxOS5kZiRwcm9fbmFtZSkKCiMgMjAxOSBidWxrIHNvaWwgdGVtcGxhdGUKc3JhLjIwMTkgPC0gc3JhLjIwMDEKCiMgaW5jIHRlbXBsYXRlcyBmb3IgbWVyZ2luZyAxNEMgZGF0YQpzcmEuMjAxOS5pbmMgPC0gdmVjdG9yKG1vZGUgPSAibGlzdCIsIGxlbmd0aCA9IGxlbmd0aCh1bmlxdWUoc3JhLjIwMTkuaW5jLmRmJHByb19uYW1lKSkpCm5hbWVzKHNyYS4yMDE5LmluYykgPC0gdW5pcXVlKHNyYS4yMDE5LmluYy5kZiRwcm9fbmFtZSkKc3JhLjIwMDEuaW5jIDwtIHNyYS4yMDE5LmluYwojIGNvcGllcyBmb3IgcmVwcyBvZiBpbmN1YmF0aW9ucwpzcmEuMjAxOS5pbmNfTCA8LSBzcmEuMjAxOS5pbmMKbmFtZXMoc3JhLjIwMTkuaW5jX0wpIDwtIHN1YnN0cihuYW1lcyhzcmEuMjAxOS5pbmNfTCksIDEsIDQpCmBgYAoKYGBge3IgYXZlcmFnZS1jbi1kYXRhfQojIGNvbXBsZXRlIGNhc2VzLCBjb252ZXJ0IHR5cGUgZm9yIGNhbGN1bGF0aW5nIHN0b2NrcyBsYXRlcgojIGNvdWxkIGNhbGN1bGF0ZSBzdG9ja3Mgbm93IGFuZCB0aGVuIHJlbW92ZSBmb3IgdGhlIGZvbGxvd2luZyBzdGVwcyB3aGVyZSBub3QgbmVlZGVkCgojIyAyMDAxIHN1bW1hcnkgZGF0YQpzb2MuMjAwMSA8LSBkYXRhLmZyYW1lKHJlYWRfZXhjZWwoIi4uL2RhdGEvZXh0ZXJuYWwvc3JhX3Jhc19zdW0vc2llcnJhX2RhdGFfc3VtbWFyeV8yMDIwLnhsc3giLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2hlZXQgPSAiMjAwMV9idWxrX2RhdGEiKSkKCiMgY3JlYXRlIGxpc3Q7IHJlbW92ZSBCUyBzYW1wbGVzIGRlZXBlciB0aGFuIDMwIGNtCnNvYy4yMDAxLmxzIDwtIGxhcHBseShzcGxpdChzb2MuMjAwMSwgc29jLjIwMDEkUE1lY28pLCBmdW5jdGlvbihkZikgewogIGRmIDwtIHR5cGUuY29udmVydChkZltjb21wbGV0ZS5jYXNlcyhkZiksIGMoIklEIiwgIkMuIiwgIm1hc3Nfa2dtMiIsICJQTWVjbyIsICJwcm9fcmVwIiwgImx5cl90b3AiLCAibHlyX2JvdCIpXSkKIHJldHVybihkZlt3aGljaChkZiRseXJfYm90IDwgMzYpLCBdKQp9KQoKIyBJbmN1YmF0aW9uIHNhbXBsZXMgY29tYmluZWQgMC0zIGFuZCAzLTggZGVwdGggaW5jcmVtZW50cyBmb3IgQlNyZiBhbmQgR1JyZgojIGNvbWJpbmUgQlNyZiBhbmQgR1JyZiBpbml0aWFsIGRlcHRocwojIGZ1bmN0aW9uIGZvciBjYWxjdWxhdGluZyB3ZWlnaHRlZCBhdmVyYWdlIG9mIGZpcnN0IHR3byBkZXB0aCBpbmNyZW1lbnQgQyBjb250ZW50CmQxZDIuZnggPC0gZnVuY3Rpb24oZGYpIHsKICBkMWQyIDwtIGRhdGEuZnJhbWUoSUQgPSBwYXN0ZShkZiRQTWVjb1sxXSwgZGYkcHJvX3JlcFsxXSwgZGYkbHlyX3RvcFsxXSwgZGYkbHlyX2JvdFsyXSwgc2VwID0gIl8iKSwKICAgICAgICAgICAgICAgICAgICAgQy4gPSBzdW0oZGYkQy5bMV0gKiAoKGRmJGx5cl9ib3RbMV0gLSBkZiRseXJfdG9wWzFdKSAvIGRmJGx5cl9ib3RbMl0pLCBkZiRDLlsyXSAqICgoZGYkbHlyX2JvdFsyXSAtIGRmJGx5cl90b3BbMl0pIC8gZGYkbHlyX2JvdFsyXSkpLAogICAgICAgICAgICAgICAgICAgICBtYXNzX2tnbTIgPSBzdW0oZGYkbWFzc19rZ20yWzFdLCBkZiRtYXNzX2tnbTJbMl0pLAogICAgICAgICAgICAgICAgICAgICBQTWVjbyA9IGRmJFBNZWNvWzFdLAogICAgICAgICAgICAgICAgICAgICBwcm9fcmVwID0gZGYkcHJvX3JlcFsxXSwKICAgICAgICAgICAgICAgICAgICAgbHlyX3RvcCA9IGRmJGx5cl90b3BbMV0sCiAgICAgICAgICAgICAgICAgICAgIGx5cl9ib3QgPSBkZiRseXJfYm90WzJdKQogIHJldHVybihyYmluZChkMWQyLAogICAgICAgICAgICAgICBkZlszOm5yb3coZGYpLCBdKSkKfQojIFJ1biBkMWQyLmZ4IGZvciBCU3JmLCBHUnJmCnNvYy4yMDAxLmxzLmluYyA8LSBzb2MuMjAwMS5scyAKc29jLjIwMDEubHMuaW5jJEdScmYgPC0gYmluZF9yb3dzKGxhcHBseShzcGxpdChzb2MuMjAwMS5scyRHUnJmLCBzb2MuMjAwMS5scyRHUnJmJHByb19yZXApLCBkMWQyLmZ4KSkKCiMgYWxzbyBuZWVkIHdlaWdodGVkICVDIGZvciBmbHV4IHdlaWdodGluZwpCU3JmX2NvbXBfMDFfcGN0QyA8LSBzb2MuMjAwMS5scy5pbmMkQlNyZlt3aGljaChzb2MuMjAwMS5scy5pbmMkQlNyZiRseXJfYm90IDwgOSksIF0KaWYgKGFueShjKGdyZXBsKCJCU3JmXzJfMCIsIEJTcmZfY29tcF8wMV9wY3RDJElEKSwgZ3JlcGwoIkJTcmZfM18wIiwgQlNyZl9jb21wXzAxX3BjdEMkSUQpKSkpIHsKICBCU3JmX2NvbXBfMDFfcGN0QyA8LSBCU3JmX2NvbXBfMDFfcGN0Q1std2hpY2goQlNyZl9jb21wXzAxX3BjdEMkSUQgPT0gIkJTcmZfM18wLTMiIHwgQlNyZl9jb21wXzAxX3BjdEMkSUQgPT0gIkJTcmZfMl8wLTMiKSwgXQp9CkJTcmZfY29tcF8wMV9wY3RDJG1hc3Nfd3QgPC0gYygxNSAvIDMwLCByZXAoKDUgLyAzMCksIDMpKQpCU3JmX2NvbXBfMDFfcGN0QyRjX3BjdF93dGQgPC0gQlNyZl9jb21wXzAxX3BjdEMkQy4gKiBCU3JmX2NvbXBfMDFfcGN0QyRtYXNzX3d0CgojIHN1bW1hcml6ZSBpbmMgU09DCnNvYy4yMDAxLmxzLmluYyA8LSBkYXRhLmZyYW1lKGJpbmRfcm93cyhsYXBwbHkoc3JhLjIwMDEubHMsIGZ1bmN0aW9uKGRmKSB7CiAgZGYgJT4lCiAgICBtdXRhdGUoSUQyID0gcGFzdGUwKFBNZWNvLCAiXyIsIGx5cl90b3AsICItIiwgbHlyX2JvdCkpICU+JQogICAgZ3JvdXBfYnkoSUQyLCBQTWVjbywgbHlyX3RvcCwgbHlyX2JvdCkgJT4lCiAgICBzdW1tYXJpemUoY19wY3RfYXZnID0gbWVhbihDLikpCn0pKSkKaWYgKGxlbmd0aCh3aGljaChzb2MuMjAwMS5zdW0yJElEMiA9PSAiQlNyZl8wLTMiIHwgc29jLjIwMDEuc3VtMiRJRDIgPT0gIkJTcmZfMy04IikpID09IDIpIHsKICBzb2MuMjAwMS5zdW0yIDwtIHNvYy4yMDAxLnN1bVstd2hpY2goc29jLjIwMDEuc3VtMiRJRDIgPT0gIkJTcmZfMC0zIiB8IHNvYy4yMDAxLnN1bTIkSUQyID09ICJCU3JmXzMtOCIpLCBdCiAgc29jLjIwMDEuc3VtMiA8LSByYmluZCgKICAgIHNvYy4yMDAxLnN1bTIsCiAgICBjKCJCU3JmXzAtOCIsICJCU3JmIiwgMCwgOCwgc3VtKEJTcmZfY29tcF8wMV9wY3RDJGNfcGN0X3d0ZCkpKQp9CgoKIyBzdW1tYXJpemUgaW5jCnNvYy4yMDAxLmluYy5zdW0gPC0gZGF0YS5mcmFtZShiaW5kX3Jvd3MobGFwcGx5KHNvYy4yMDAxLmxzLmluYywgZnVuY3Rpb24oZGYpIHsKICBkZiAlPiUKICAgIG11dGF0ZShJRDIgPSBwYXN0ZTAoUE1lY28sICJfIiwgbHlyX3RvcCwgIi0iLCBseXJfYm90KSkgJT4lCiAgICBncm91cF9ieShJRDIsIFBNZWNvLCBseXJfdG9wLCBseXJfYm90KSAlPiUKICAgIHN1bW1hcml6ZShjX3BjdF9hdmcgPSBtZWFuKEMuKSkKfSkpKQpzYXZlKHNvYy4yMDAxLmluYy5zdW0sIGZpbGUgPSAic29jLjIwMDEuaW5jLnN1bS5SRGF0YSIpCgojIGNhbGN1bGF0ZSBTT0Mgc3RvY2tzCnNvYy4yMDAxLmxzIDwtIGxhcHBseShzb2MuMjAwMS5scywgZnVuY3Rpb24oZGYpIHsKICBkZiRseXJfc29jX2tnbTIgPC0gZGYkQy4gKiBkZiRtYXNzX2tnbTIgKiAxMF4tMgogIHJldHVybihkZikKfSkKCiMgMjAxOSBkYXRhCnNyYS4yMDE5LmNuLnN1bSA8LSBkYXRhLmZyYW1lKAogIGJpbmRfcm93cyh1bmxpc3QoZWxtX3Jlc3VsdHNfbHMsIHJlY3Vyc2l2ZSA9IEZBTFNFKSkgJT4lCiAgbXV0YXRlKFBNZWNvID0gc2FwcGx5KHN0cnNwbGl0KElELCAiXyIpLCAiWyIsIDIpLAogICAgICAgICBkZXB0aCA9IHNhcHBseShzdHJzcGxpdChJRCwgIl8iKSwgIlsiLCA0KSkgJT4lCiAgZ3JvdXBfYnkoUE1lY28sIGRlcHRoKSAlPiUKICBzdW1tYXJpemUoYWNyb3NzKGMoQywgTiksIC5mbnMgPSBtZWFuKSkpICU+JQogIHJlbmFtZShjX3BjdF9hdmcgPSBDLAogICAgICAgICBuX3BjdF9hdmcgPSBOKQpzcmEuMjAxOS5jbi5zdW0kSUQyIDwtIHBhc3RlKHNyYS4yMDE5LmNuLnN1bSRQTWVjbywgc3JhLjIwMTkuY24uc3VtJGRlcHRoLCBzZXAgPSAiXyIpCnNhdmUoc3JhLjIwMTkuY24uc3VtLCBmaWxlID0gInNyYS4yMDE5LmNuLnN1bS5SRGF0YSIpCmBgYAoKKk1lcmdlIHRlbXBsYXRlcyB3aXRoIDE0QywgQywgYW5kIE4gZGF0YSoKClJhZGlvY2FyYm9uIGFuYWx5c2VzIGZvciB0aGUgMjAwMSBzYW1wbGVzIHdlcmUgbm90IHJ1biBvcmlnaW5hbGx5LCBidXQgd2VyZSBjb21wbGV0ZWQgb24gYXJjaGl2ZWQgc2FtcGxlcyBpbiAyMDIwLgoKYGBge3IgbWVyZ2UtaXNvLWRhdGEtUzAxLXNvaWx9CiMgRXh0cmFjdCAxNEMgZGF0YSBmb3IgMjAwMSBzYW1wbGVzCmFtc19yZXN1bHRzX2xzX1MwMSA8LSBhbXNfcmVzdWx0c19sc1tncmVwKCJTMDEiLCBuYW1lcyhhbXNfcmVzdWx0c19scykpXQpmb3IoaSBpbiBzZXFfYWxvbmcoc3JhLjIwMDEpKSB7CiAgc3JhLjIwMDFbW2ldXSA8LSBsYXBwbHkoYW1zX3Jlc3VsdHNfbHNfUzAxLCBmdW5jdGlvbihscykgewogICAgbGFwcGx5KGxzLCBmdW5jdGlvbihkZikgewogICAgICBpZihhbnkoZ3JlcGwobmFtZXMoc3JhLjIwMDEpW2ldLCBkZiRQcm9iZSkpKSB7CiAgICAgICBkZltncmVwKG5hbWVzKHNyYS4yMDAxKVtpXSwgZGYkUHJvYmUpLCBdIAogICAgICB9CiAgICB9KQogIH0pCiAgc3JhLjIwMDFbW2ldXSA8LSBGaWx0ZXIoTmVnYXRlKGlzLm51bGwpLCB1bmxpc3Qoc3JhLjIwMDFbW2ldXSwgcmVjdXJzaXZlID0gRkFMU0UpKQp9CnNyYS4yMDAxIDwtIGJpbmRfcm93cyh1bmxpc3Qoc3JhLjIwMDEsIHJlY3Vyc2l2ZSA9IEZBTFNFKSkKCiMgY3JlYXRlIElEIGZpZWxkLCB0cmltIGRmLCBhbmQgYWRkIGRlcHRocwpzcmEuMjAwMSRJRCA8LSB1bmxpc3Qoc3Ryc3BsaXQoc3JhLjIwMDEkUHJvYmUsICJfU2llcnJhIE5ldmFkYV8yMDAxIikpCnNyYS4yMDAxIDwtIHNyYS4yMDAxWyAsIGMoIklEIiwgIkYxNEMiLCAiZXJyIiwgIuKIhjE0Qy4o4oCwKSIsICJlcnIuKOKAsCkiKV0KbmFtZXMoc3JhLjIwMDEpIDwtIGMoIklEIiwgImZtIiwgImZtX2VyciIsICJkMTRjIiwgImQxNGNfZXJyIikKc3JhLjIwMDEkbHlyX3RvcCA8LSBhcy5udW1lcmljKGlmZWxzZShzdWJzdHIoc3JhLjIwMDEkSUQsIDksIDkpID09ICItIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdWJzdHIoc3JhLjIwMDEkSUQsIDgsIDgpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1YnN0cihzcmEuMjAwMSRJRCwgOCwgOSkpKQpzcmEuMjAwMSRseXJfYm90IDwtIGFzLm51bWVyaWMoaWZlbHNlKHN1YnN0cihzcmEuMjAwMSRJRCwgOSwgOSkgPT0gIi0iLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdWJzdHIoc3JhLjIwMDEkSUQsIDEwLCBuY2hhcihzcmEuMjAwMSRJRCkpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1YnN0cihzcmEuMjAwMSRJRCwgMTEsIG5jaGFyKHNyYS4yMDAxJElEKSkpKQpzcmEuMjAwMSRwcm9fcmVwIDwtIHN1YnN0cihzcmEuMjAwMSRJRCwgNiwgNikKc3JhLjIwMDEkUE0gPC0gZmFjdG9yKHN1YnN0cihzcmEuMjAwMSRJRCwgMSwgMikpCnNyYS4yMDAxJEVDTyA8LSBmYWN0b3Ioc3Vic3RyKHNyYS4yMDAxJElELCAzLCA0KSwgbGV2ZWxzID0gYygicHAiLCAid2YiLCAicmYiKSkKc3JhLjIwMDEkcHJvX25hbWUgPC0gc3Vic3RyKHNyYS4yMDAxJElELCAxLCA2KQpzcmEuMjAwMSRQTWVjbyA8LSBzdWJzdHIoc3JhLjIwMDEkSUQsIDEsIDQpCgojIHJlbW92ZSBvdXRsaWVyIEFOcHAgc2FtcGxlCnNyYS4yMDAxIDwtIHNyYS4yMDAxWy13aGljaChzcmEuMjAwMSRJRCA9PSAiQU5wcF8zXzYtMTMiKSwgXQoKIyBtYWtlIGxpc3QgYnkgUE1lY28Kc3JhLjIwMDEubHMgPC0gc3BsaXQoc3JhLjIwMDEsIHNyYS4yMDAxJFBNZWNvKQpgYGAKCmBgYHtyIG1lcmdlLWlzby1kYXRhLXNvaWwtUzE5fQojIEV4dHJhY3QgMTRDIGRhdGEgZm9yIDIwMTkgc2FtcGxlcwphbXNfcmVzdWx0c19sc19TMTkgPC0gYW1zX3Jlc3VsdHNfbHNbZ3JlcCgic29pbC1TMTkiLCBuYW1lcyhhbXNfcmVzdWx0c19scykpXQpmb3IoaSBpbiBzZXFfYWxvbmcoc3JhLjIwMTkpKSB7CiAgc3JhLjIwMTlbW2ldXSA8LSBsYXBwbHkoYW1zX3Jlc3VsdHNfbHNfUzE5LCBmdW5jdGlvbihscykgewogICAgbGFwcGx5KGxzLCBmdW5jdGlvbihkZikgewogICAgICBpZihhbnkoZ3JlcGwobmFtZXMoc3JhLjIwMTkpW2ldLCBkZiRQcm9iZSkpKSB7CiAgICAgICBkZltncmVwKG5hbWVzKHNyYS4yMDE5KVtpXSwgZGYkUHJvYmUpLCBdIAogICAgICB9CiAgICB9KQogIH0pCiAgc3JhLjIwMTlbW2ldXSA8LSBGaWx0ZXIoTmVnYXRlKGlzLm51bGwpLCB1bmxpc3Qoc3JhLjIwMTlbW2ldXSwgcmVjdXJzaXZlID0gRkFMU0UpKQp9CnNyYS4yMDE5IDwtIGJpbmRfcm93cyh1bmxpc3Qoc3JhLjIwMTksIHJlY3Vyc2l2ZSA9IEZBTFNFKSkKCiMjIG1lcmdlIHcvIDIwMTkgdGVtcGxhdGUKIyByZW5hbWUgY29scyBpbiBBTVMgdGFibGVzCnNyYS4yMDE5IDwtIHNyYS4yMDE5WyAsIGMoIlByb2JlIiwgIkYxNEMiLCAiZXJyIiwgIuKIhjE0Qy4o4oCwKSIsICJlcnIuKOKAsCkiKV0KbmFtZXMoc3JhLjIwMTkpIDwtIGMoIklEIiwgImZtIiwgImZtX2VyciIsICJkMTRjIiwgImQxNGNfZXJyIikKIyBtZXJnZQpzcmEuMjAxOS5scyA8LSBsYXBwbHkoc3BsaXQoc3JhLjIwMTkuZGYsIHNyYS4yMDE5LmRmJGx5cl9uYW1lKSwgZnVuY3Rpb24oZGYpIHsKICBkZiA8LSBtZXJnZShkZiwgc3JhLjIwMTlbZ3JlcChkZiRseXJfbmFtZSwgc3JhLjIwMTkkSUQpLCBdKQogIGRmJElEIDwtIE5VTEwKICBkZiRQTWVjbyA8LSBwYXN0ZTAoZGYkUE0sIGRmJEVDTykKICByZXR1cm4oZGYpCn0pCgojIHJlc2hhcGUgbGlzdCBieSBQTWVjbwpzcmEuMjAxOS5scyA8LSBzcGxpdChiaW5kX3Jvd3Moc3JhLjIwMTkubHMpLCBiaW5kX3Jvd3Moc3JhLjIwMTkubHMpW1siUE1lY28iXV0pCmBgYAoKYGBge3IgbWVyZ2UtaXNvLWRhdGEtY28yfQojIyMgRXh0cmFjdCAxNEMgZGF0YSBmb3IgaW5jdWJhdGlvbiBzYW1wbGVzCiMjIHJlc3BpcmVkIENPMiwgc29pbAojIDIwMTkKYW1zX3Jlc3VsdHNfbHNfY28yX1MxOSA8LSBhbXNfcmVzdWx0c19sc1tncmVwKCJjbzItUzE5IiwgbmFtZXMoYW1zX3Jlc3VsdHNfbHMpKV0KZm9yIChpIGluIHNlcV9hbG9uZyhzcmEuMjAxOS5pbmMpKSB7CiAgc3JhLjIwMTkuaW5jW1tpXV0gPC0gbGFwcGx5KGFtc19yZXN1bHRzX2xzX2NvMl9TMTksIGZ1bmN0aW9uKGxzKSB7CiAgICBsYXBwbHkobHMsIGZ1bmN0aW9uKGRmKSB7CiAgICAgIGlmIChhbnkoZ3JlcGwobmFtZXMoc3JhLjIwMTkuaW5jKVtpXSwgZGYkUHJvYmUpKSkgewogICAgICAgIGRmW2dyZXAobmFtZXMoc3JhLjIwMTkuaW5jKVtpXSwgZGYkUHJvYmUpLCBdIAogICAgICB9CiAgICB9KQogIH0pCiAgc3JhLjIwMTkuaW5jW1tpXV0gPC0gRmlsdGVyKE5lZ2F0ZShpcy5udWxsKSwgdW5saXN0KHNyYS4yMDE5LmluY1tbaV1dLCByZWN1cnNpdmUgPSBGQUxTRSkpCn0Kc3JhLjIwMTkuaW5jIDwtIHR5cGUuY29udmVydCgKICBiaW5kX3Jvd3MoCiAgICBsYXBwbHkodW5saXN0KHNyYS4yMDE5LmluYywgcmVjdXJzaXZlID0gRkFMU0UpLCAKICAgICAgICAgICBmdW5jdGlvbih4KSB4ICU+JSBtdXRhdGVfYWxsKGFzLmNoYXJhY3RlcikpKSwKICBhcy5pcyA9IFRSVUUpCnNyYS4yMDE5LmluYyA8LSBzcmEuMjAxOS5pbmNbLXdoaWNoKGlzLm5hKHNyYS4yMDE5LmluYyRGMTRDKSksIF0KCiMgMjAwMQphbXNfcmVzdWx0c19sc19jbzJfUzAxIDwtIGFtc19yZXN1bHRzX2xzW2dyZXAoImNvMi1TMDEiLCBuYW1lcyhhbXNfcmVzdWx0c19scykpXQojIHJlbW92ZSBxdWVzdGlvbmFibGUvZHVwbGljYXRlIHNhbXBsZXMKIyBBTnJmX2NvbXBfMTEtMzJfMjAwMV9hIChhbmFseXplZCB0d2ljZTsgYm90aCBhbm9tb3VzbHkgbG93IGNvbXBhcmVkIHRvIHJlcCBhbmQgcmVzdCBvZiBkYXRhKQphbXNfcmVzdWx0c19sc19jbzJfUzAxJGBhbXNfamVuYV9yZXN1bHRzLWNvMi1TMDFfMjAyMC0xMi0xMWAkYEJlZW0tTWlsbGVyXzIyLnhsc3hgIDwtIGFtc19yZXN1bHRzX2xzX2NvMl9TMDEkYGFtc19qZW5hX3Jlc3VsdHMtY28yLVMwMV8yMDIwLTEyLTExYCRgQmVlbS1NaWxsZXJfMjIueGxzeGBbLWdyZXAoIkFOcmZfY29tcF8xMS0zMl8yMDAxX2EiLCBhbXNfcmVzdWx0c19sc19jbzJfUzAxJGBhbXNfamVuYV9yZXN1bHRzLWNvMi1TMDFfMjAyMC0xMi0xMWAkYEJlZW0tTWlsbGVyXzIyLnhsc3hgJFByb2JlKSwgXQphbXNfcmVzdWx0c19sc19jbzJfUzAxJGBhbXNfamVuYV9yZXN1bHRzLWNvMi1TMDFfMjAyMC0xMi0xNmAkYDE0Q19TaWVycmFOZXZhZGFfSW5jXzIwMDFfM19yZXN1bHRzLnhsc3hgIDwtIGFtc19yZXN1bHRzX2xzX2NvMl9TMDEkYGFtc19qZW5hX3Jlc3VsdHMtY28yLVMwMV8yMDIwLTEyLTE2YCRgMTRDX1NpZXJyYU5ldmFkYV9JbmNfMjAwMV8zX3Jlc3VsdHMueGxzeGBbLWdyZXAoIkFOcmZfY29tcF8xMS0zMl8yMDAxX2EiLCBhbXNfcmVzdWx0c19sc19jbzJfUzAxJGBhbXNfamVuYV9yZXN1bHRzLWNvMi1TMDFfMjAyMC0xMi0xNmAkYDE0Q19TaWVycmFOZXZhZGFfSW5jXzIwMDFfM19yZXN1bHRzLnhsc3hgJFByb2JlKSwgXQojIGZyb20gb3JpZ2luYWwgYW5hbHlzaXMgb2Ygc2FtcGxlcyBleHRyYWN0ZWQgb25saW5lIDExLURlYy0yMDIwIChzZWUgcmVhZG1lIGZvciBub3RlcykKYW1zX3Jlc3VsdHNfbHNfY28yX1MwMSRgYW1zX2plbmFfcmVzdWx0cy1jbzItUzAxXzIwMjAtMTItMTFgJGBCZWVtLU1pbGxlcl8yMy54bHN4YCA8LSBhbXNfcmVzdWx0c19sc19jbzJfUzAxJGBhbXNfamVuYV9yZXN1bHRzLWNvMi1TMDFfMjAyMC0xMi0xMWAkYEJlZW0tTWlsbGVyXzIzLnhsc3hgWy1ncmVwKCJHUndmX2NvbXBfMTMtMjhfMjAwMV9hXzExIiwgYW1zX3Jlc3VsdHNfbHNfY28yX1MwMSRgYW1zX2plbmFfcmVzdWx0cy1jbzItUzAxXzIwMjEtMDEtMjZgJGAxNENfU2llcnJhTmV2YWRhX0luY18yMDAxXzJfcmVzdWx0cy54bHN4YCRQcm9iZSksIF0KIyBmcm9tIHJlYW5hbHlzaXMgb2Ygc2FtcGxlcyBleHRyYWN0ZWQgb25saW5lIDExLURlYy0yMDIwIChzZWUgcmVhZG1lIGZvciBub3RlcykKIyBHUnJmX2NvbXBfOC0yN18yMDAxX2FfNSwgR1JyZl9jb21wXzgtMjdfMjAwMV9iXzYsIEdScHBfY29tcF8xNS0yN18yMDAxX2JfMTggCmFtc19yZXN1bHRzX2xzX2NvMl9TMDEkYGFtc19qZW5hX3Jlc3VsdHMtY28yLVMwMV8yMDIxLTAxLTI2YCRgMTRDX1NpZXJyYU5ldmFkYV9JbmNfMjAwMV8yX3Jlc3VsdHMueGxzeGAgPC0gYW1zX3Jlc3VsdHNfbHNfY28yX1MwMSRgYW1zX2plbmFfcmVzdWx0cy1jbzItUzAxXzIwMjEtMDEtMjZgJGAxNENfU2llcnJhTmV2YWRhX0luY18yMDAxXzJfcmVzdWx0cy54bHN4YFtjKAogIGdyZXAoIkdScmZfY29tcF84LTI3XzIwMDFfYV81IiwgYW1zX3Jlc3VsdHNfbHNfY28yX1MwMSRgYW1zX2plbmFfcmVzdWx0cy1jbzItUzAxXzIwMjEtMDEtMjZgJGAxNENfU2llcnJhTmV2YWRhX0luY18yMDAxXzJfcmVzdWx0cy54bHN4YCRQcm9iZSksCiAgZ3JlcCgiR1J3Zl9jb21wXzEzLTI4XzIwMDFfYl8xMiIsIGFtc19yZXN1bHRzX2xzX2NvMl9TMDEkYGFtc19qZW5hX3Jlc3VsdHMtY28yLVMwMV8yMDIxLTAxLTI2YCRgMTRDX1NpZXJyYU5ldmFkYV9JbmNfMjAwMV8yX3Jlc3VsdHMueGxzeGAkUHJvYmUpKSwgXQoKIyBjcmVhdGUgdGVtcGxhdGUgZm9yIGV4dHJhY3RpbmcgZGF0YQpzcmEuMjAwMS5pbmMgPC0gdmVjdG9yKG1vZGUgPSAibGlzdCIsIGxlbmd0aCA9IGxlbmd0aCh1bmlxdWUoc3JhLjIwMTkuaW5jLmRmJHByb19uYW1lKSkpCm5hbWVzKHNyYS4yMDAxLmluYykgPC0gdW5pcXVlKHNyYS4yMDE5LmluYy5kZiRwcm9fbmFtZSkKIyBtZXJnZSB3aXRoIDE0QyBkYXRhCmZvciAoaSBpbiBzZXFfYWxvbmcoc3JhLjIwMDEuaW5jKSkgewogIHNyYS4yMDAxLmluY1tbaV1dIDwtIGxhcHBseShhbXNfcmVzdWx0c19sc19jbzJfUzAxLCBmdW5jdGlvbihscykgewogICAgbGFwcGx5KGxzLCBmdW5jdGlvbihkZikgewogICAgICBpZiAoYW55KGdyZXBsKG5hbWVzKHNyYS4yMDAxLmluYylbaV0sIGRmJFByb2JlKSkpIHsKICAgICAgICBkZltncmVwKG5hbWVzKHNyYS4yMDAxLmluYylbaV0sIGRmJFByb2JlKSwgXSAKICAgICAgfQogICAgfSkKICB9KQogIHNyYS4yMDAxLmluY1tbaV1dIDwtIEZpbHRlcihOZWdhdGUoaXMubnVsbCksIHVubGlzdChzcmEuMjAwMS5pbmNbW2ldXSwgcmVjdXJzaXZlID0gRkFMU0UpKQp9CnNyYS4yMDAxLmluYyA8LSB0eXBlLmNvbnZlcnQoCiAgYmluZF9yb3dzKAogICAgbGFwcGx5KHVubGlzdChzcmEuMjAwMS5pbmMsIHJlY3Vyc2l2ZSA9IEZBTFNFKSwgCiAgICAgICAgICAgZnVuY3Rpb24oeCkgeCAlPiUgbXV0YXRlX2FsbChhcy5jaGFyYWN0ZXIpKSksCiAgYXMuaXMgPSBUUlVFKQpzcmEuMjAwMS5pbmMgPC0gc3JhLjIwMDEuaW5jWy13aGljaChpcy5uYShzcmEuMjAwMS5pbmMkRjE0QykpLCBdCgojIHJlc3BpcmVkIENPMiwgbGl0dGVyCmFtc19yZXN1bHRzX2xzX2NvMl9MMTkgPC0gYW1zX3Jlc3VsdHNfbHNbZ3JlcCgiY28yLUwxOSIsIG5hbWVzKGFtc19yZXN1bHRzX2xzKSldCmZvcihpIGluIHNlcV9hbG9uZyhzcmEuMjAxOS5pbmNfTCkpIHsKICBzcmEuMjAxOS5pbmNfTFtbaV1dIDwtIGxhcHBseShhbXNfcmVzdWx0c19sc19jbzJfTDE5LCBmdW5jdGlvbihscykgewogICAgbGFwcGx5KGxzLCBmdW5jdGlvbihkZikgewogICAgICBpZihhbnkoZ3JlcGwobmFtZXMoc3JhLjIwMTkuaW5jX0wpW2ldLCBkZiRQcm9iZSkpKSB7CiAgICAgICBkZltncmVwKG5hbWVzKHNyYS4yMDE5LmluY19MKVtpXSwgZGYkUHJvYmUpLCBdIAogICAgICB9CiAgICB9KQogIH0pCiAgc3JhLjIwMTkuaW5jX0xbW2ldXSA8LSBGaWx0ZXIoTmVnYXRlKGlzLm51bGwpLCB1bmxpc3Qoc3JhLjIwMTkuaW5jX0xbW2ldXSwgcmVjdXJzaXZlID0gRkFMU0UpKQp9CnNyYS4yMDE5LmluY19MIDwtIGJpbmRfcm93cyh1bmxpc3Qoc3JhLjIwMTkuaW5jX0wsIHJlY3Vyc2l2ZSA9IEZBTFNFKSkKCiMjIG1lcmdlIHcvIHRlbXBsYXRlcyBbd2h5IGRvIEkgZG8gdGhpcyB0d2ljZT9dCiMgcmVuYW1lIGNvbHMgaW4gQU1TIHRhYmxlcwojIHNvaWwgQ08yCnNyYS4yMDE5LmluYyA8LSBzcmEuMjAxOS5pbmNbICwgYygiUHJvYmUiLCAiRjE0QyIsICJlcnIiLCAi4oiGMTRDLijigLApIiwgImVyci4o4oCwKSIpXQpuYW1lcyhzcmEuMjAxOS5pbmMpIDwtIGMoIklEIiwgImZtIiwgImZtX2VyciIsICJkMTRjIiwgImQxNGNfZXJyIikKc3JhLjIwMDEuaW5jIDwtIHNyYS4yMDAxLmluY1sgLCBjKCJQcm9iZSIsICJGMTRDIiwgImVyciIsICLiiIYxNEMuKOKAsCkiLCAiZXJyLijigLApIildCm5hbWVzKHNyYS4yMDAxLmluYykgPC0gYygiSUQiLCAiZm0iLCAiZm1fZXJyIiwgImQxNGMiLCAiZDE0Y19lcnIiKQojIG1lcmdlCiMgMjAxOQpzcmEuMjAxOS5pbmMubHMgPC0gYmluZF9yb3dzKAogIGxhcHBseShzcGxpdChzcmEuMjAxOS5pbmMuZGYsIHNyYS4yMDE5LmluYy5kZiRseXJfbmFtZSksIGZ1bmN0aW9uKGRmKSB7CiAgICBkZiA8LSBtZXJnZShkZiwgc3JhLjIwMTkuaW5jW2dyZXAoZGYkbHlyX25hbWUsIHNyYS4yMDE5LmluYyRJRCksIF0pCiAgICBkZiRJRCA8LSBOVUxMCiAgICBkZiRQTWVjbyA8LSBwYXN0ZTAoZGYkUE0sIGRmJEVDTykKICAgIHJldHVybihkZikKICB9KQopCnNyYS4yMDE5LmluYy5scyA8LSBzcGxpdChzcmEuMjAxOS5pbmMubHMsIHNyYS4yMDE5LmluYy5scyRQTWVjbykKIyAyMDAxCnNyYS4yMDAxLmluYy5scyA8LSBiaW5kX3Jvd3MoCiAgbGFwcGx5KHNwbGl0KHNyYS4yMDAxLmluYy5kZiwgc3JhLjIwMDEuaW5jLmRmJGx5cl9uYW1lKSwgZnVuY3Rpb24oZGYpIHsKICAgIGRmIDwtIG1lcmdlKGRmLCBzcmEuMjAwMS5pbmNbZ3JlcChkZiRseXJfbmFtZSwgc3JhLjIwMDEuaW5jJElEKSwgXSkKICAgIGRmJElEIDwtIE5VTEwKICAgIGRmJFBNZWNvIDwtIHBhc3RlMChkZiRQTSwgZGYkRUNPKQogICAgcmV0dXJuKGRmKQogIH0pCikKc3JhLjIwMDEuaW5jLmxzIDwtIHNwbGl0KHNyYS4yMDAxLmluYy5scywgc3JhLjIwMDEuaW5jLmxzJFBNZWNvKQoKIyBzYXZlIGluYyBsaXN0CnNhdmUoc3JhLjIwMDEuaW5jLmxzLCBmaWxlID0gInNyYS4yMDAxLmluYy5scy5SRGF0YSIpCgojIGxpdHRlciBDTzIKc3JhLjIwMTkuaW5jX0wgPC0gc3JhLjIwMTkuaW5jX0xbICwgYygiUHJvYmUiLCAiRjE0QyIsICJlcnIiLCAi4oiGMTRDLijigLApIiwgImVyci4o4oCwKSIpXQpuYW1lcyhzcmEuMjAxOS5pbmNfTCkgPC0gYygiSUQiLCAiZm0iLCAiZm1fZXJyIiwgImQxNGMiLCAiZDE0Y19lcnIiKQpzcmEuMjAxOS5pbmNfTCRJRCA8LSBzdWJzdHIoc3Vic3RyaW5nKHNyYS4yMDE5LmluY19MJElELCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZWdleHByKCJfIiwgc3JhLjIwMTkuaW5jX0wkSUQpICsgMSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmNoYXIoc3JhLjIwMTkuaW5jX0wkSUQpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIDEsIDgpCnNyYS4yMDE5LmluYy5kZl9MIDwtIGRhdGEuZnJhbWUoWWVhciA9IHJlcCgyMDE5LCAxOCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVwID0gcmVwKGMoMSwgMiksIDkpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFBNID0gcmVwKGMoIkFOIiwgIkJTIiwgIkdSIiksIGVhY2ggPSA2KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlY28gPSByZXAoYygicHAiLCAid2YiLCAicmYiKSwgZWFjaCA9IDIsIHRpbWVzID0gMykpCnNyYS4yMDE5LmluYy5kZl9MJFBNZWNvIDwtIHBhc3RlMChzcmEuMjAxOS5pbmMuZGZfTCRQTSwgc3JhLjIwMTkuaW5jLmRmX0wkZWNvKQpzcmEuMjAxOS5pbmMuZGZfTCRJRCA8LSBwYXN0ZTAoc3JhLjIwMTkuaW5jLmRmX0wkUE0sIHNyYS4yMDE5LmluYy5kZl9MJGVjbywgIi1MXyIsIHNyYS4yMDE5LmluYy5kZl9MJHJlcCkKIyBhZGQgZHJ5IHd0cyBhbmQgbGl0dGVyIGRlcHRoCnNyYS4yMDE5LkwgPC0gcmVhZC5jc3YoIi4uL2RhdGEvZGVyaXZlZC9sYWJfamVuYV9saXR0ZXIvTGl0dGVyXzIwMTlfMjAyMS0wMS0yNy5jc3YiKQpzcmEuMjAxOS5pbmMuZGZfTCA8LSBtZXJnZShzcmEuMjAxOS5pbmMuZGZfTCwgc3JhLjIwMTkuTFsgLCBjKCJQTWVjbyIsICJseXJfdG9wIiwgImx5cl9ib3QiKV0sIGFsbC54ID0gVFJVRSkKIyBtZXJnZQpzcmEuMjAxOS5pbmNfTC5kZiA8LSBiaW5kX3Jvd3MoCiAgbGFwcGx5KHNwbGl0KHNyYS4yMDE5LmluY19MLCBzcmEuMjAxOS5pbmNfTCRJRCksIGZ1bmN0aW9uKGRmKSB7CiAgICBkZiA8LSBtZXJnZShkZiwgc3JhLjIwMTkuaW5jLmRmX0wsIGJ5ID0gIklEIikKICAgIGRmJElEIDwtIE5VTEwKICAgIHJldHVybihkZikKICB9KQopCnNyYS4yMDE5LmluY19MLmxzIDwtIHNwbGl0KHNyYS4yMDE5LmluY19MLmRmLCBzcmEuMjAxOS5pbmNfTC5kZiRQTWVjbykKYGBgCgpgYGB7ciBwbG90LXV0aWxzfQojIGZtIGFuZCBkMTRjIGNvbnZlcnNpb24gZnVuY3Rpb25zCmxhbWJkYSA8LSAxLzgyNjcgIyA9IDEvKHRydWUgbWVhbiBsaWZlIG9mIDE0QykKY2FsY19mbSA8LSBmdW5jdGlvbihkMTRjLCBvYnNfZGF0ZV95KSB7CiAgKChkMTRjLzEwMDApICsgMSkvZXhwKGxhbWJkYSAqICgxOTUwIC0gb2JzX2RhdGVfeSkpCn0KY2FsY18xNGMgPC0gZnVuY3Rpb24oZm0sIG9ic19kYXRlX3kpIHsKICAoZm0gKiBleHAobGFtYmRhICogKDE5NTAgLSBvYnNfZGF0ZV95KSkgLSAxKSAqIDEwMDAKfQoKIyBjYWxjIGF0bSBpbiAyMDAxLCAyMDA5LCAyMDE5CkRhdG0gPC0gcmJpbmQoZ3JhdmVuLCBmdXR1cmUxNEMpCmF0bS5kMTQuMjAwMSA8LSBEYXRtW0RhdG0kRGF0ZSA9PSAyMDAxLjUsICJOSGMxNCJdCmF0bS5mbS4yMDAxIDwtIGNhbGNfZm0oYXRtLmQxNC4yMDAxLCAyMDAxKQphdG0uZDE0LjIwMDkgPC0gRGF0bVtEYXRtJERhdGUgPT0gMjAwOS41LCAiTkhjMTQiXQphdG0uZm0uMjAwOSA8LSBjYWxjX2ZtKGF0bS5kMTQuMjAwOSwgMjAwOSkKYXRtLmQxNC4yMDE5IDwtIERhdG1bRGF0bSREYXRlID09IDIwMTkuNSwgIk5IYzE0Il0KYXRtLmZtLjIwMTkgPC0gY2FsY19mbShhdG0uZDE0LjIwMTksIDIwMTkpCmBgYAoKYGBge3IgcGxvdC1saXR0ZXItMTRjfQpmaWcubiA8LSBmaWcubiArIDEKIyBzdW1tYXJpemUgbGl0dGVyIGluYyBkYXRhCnNyYS4yMDE5LmluY19MLnN1bSA8LSBzcmEuMjAxOS5pbmNfTC5kZiAlPiUKICBtdXRhdGUoZWNvID0gZmFjdG9yKGlmZWxzZShlY28gPT0gInBwIiwgIndhcm0iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShlY28gPT0gIndmIiwgImNvb2wiLCAiY29sZCIpKSwKICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoIndhcm0iLCAiY29vbCIsICJjb2xkIikpLAogICAgICAgICBwbSA9IGZhY3RvcihpZmVsc2UoUE0gPT0gIkFOIiwgImFuZGVzaXRlIiwKICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKFBNID09ICJCUyIsICJiYXNhbHQiLCAiZ3Jhbml0ZSIpKSksCiAgICAgICAgIFllYXIgPSBmYWN0b3IoIjIwMTkiKSkgJT4lCiAgZ3JvdXBfYnkoWWVhciwgUE1lY28sIHBtLCBlY28sIGx5cl90b3AsIGx5cl9ib3QpICU+JQogIHN1bW1hcml6ZShkMTRjX21lYW4gPSBtZWFuKGQxNGMpLAogICAgICAgICAgICBkMTRjX3UgPSBtYXgoZDE0YyksCiAgICAgICAgICAgIGQxNGNfbCA9IG1pbihkMTRjKSwKICAgICAgICAgICAgZm1fbWVhbiA9IG1lYW4oZm0pLAogICAgICAgICAgICBmbV91ID0gbWF4KGZtKSwKICAgICAgICAgICAgZm1fbCA9IG1pbihmbSkpCgojIHBsb3QgYXMgY29scyBieSBjbGltYXRlCnNyYS4yMDE5LmluY19MLnN1bSAlPiUKICBtdXRhdGUoTUFUID0gZmFjdG9yKGVjbywgbGV2ZWxzID0gYygid2FybSIsICJjb29sIiwgImNvbGQiKSwgbGFiZWxzID0gYygiMTAtMTMiLCAiOC0xMCIsICI1LTYiKSkpICU+JQogIGdncGxvdCguLCBhZXMoTUFULCBkMTRjX21lYW4sIGZpbGwgPSBwbSkpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gYXRtLmQxNC4yMDE5LCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgZ2VvbV9jb2wocG9zaXRpb24gPSAiZG9kZ2UyIikgKwogIGdlb21fZXJyb3JiYXIoYWVzKHltYXggPSBkMTRjX3UsIHltaW4gPSBkMTRjX2wsIGNvbG9yID0gcG0pLCAKICAgICAgICAgICAgICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2UyKHdpZHRoID0gLjUsIHBhZGRpbmcgPSAuNSkpICsKICBzY2FsZV9maWxsX21hbnVhbChuYW1lID0gIlBhcmVudCBtYXRlcmlhbCIsCiAgICAgICAgICAgICAgICAgICAgdmFsdWVzID0gYygiYW5kZXNpdGUiID0gImJsdWUiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJiYXNhbHQiID0gInJlZCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImdyYW5pdGUiID0gImRhcmtncmF5IikpICsKICBzY2FsZV9jb2xvcl9tYW51YWwobmFtZSA9ICJQYXJlbnQgbWF0ZXJpYWwiLAogICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSBjKCJhbmRlc2l0ZSIgPSAiYmx1ZSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJiYXNhbHQiID0gInJlZCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJncmFuaXRlIiA9ICJkYXJrZ3JheSIpKSArCiAgY29vcmRfZmxpcCgpICsKICB5bGFiKGV4cHJlc3Npb24oRGVsdGEqJydeMTQqJ0MgKOKAsCknKSkgKwogIHhsYWIoZXhwcmVzc2lvbigiTUFUICgiKn5kZWdyZWUqQyoiKSIpKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUocGFuZWwuZ3JpZCA9IGVsZW1lbnRfYmxhbmsoKSkKCiMgcGxvdCBhcyBwb2ludHMgd2l0aCBkZXB0aApzcmEuMjAxOS5pbmNfTC5zdW0gJT4lCiAgZ2dwbG90KC4sIGFlcyhkMTRjX21lYW4sIGx5cl90b3AsIGNvbG9yID0gcG0pKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMCkgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDApICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBhdG0uZDE0LjIwMTksIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICBnZW9tX3BvaW50KHNpemUgPSAzKSArCiAgZ2VvbV9lcnJvcmJhcmgoYWVzKHhtYXggPSBkMTRjX3UsIHhtaW4gPSBkMTRjX2wpLCBoZWlnaHQgPSAxKSArCiAgc2NhbGVfeV9yZXZlcnNlKCkgKwogIHNjYWxlX2NvbG9yX21hbnVhbChuYW1lID0gIlBhcmVudCBtYXRlcmlhbCIsCiAgICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9IGMoImFuZGVzaXRlIiA9ICJibHVlIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImJhc2FsdCIgPSAicmVkIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImdyYW5pdGUiID0gImRhcmtncmF5IikpICsKICBmYWNldF9ncmlkKHJvd3MgPSB2YXJzKGVjbykpICsKICB4bGFiKGV4cHJlc3Npb24oRGVsdGEqJydeMTQqJ0MgKOKAsCknKSkgKwogIHlsYWIoIkRlcHRoIChjbSkiKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUocGFuZWwuZ3JpZCA9IGVsZW1lbnRfYmxhbmsoKSkKYGBgCj4qKkZpZy4gYHIge2ZpZy5ufWAuIExpdHRlciBpbmN1YmF0aW9uICRcRGVsdGEkXjE0XkMtQ09+Mn4gKDIwMTkpKioKCj4qQ2FwdGlvbjoqIE1lYW4gJFxEZWx0YSReMTReQy1DT34yfiBmb3IgZWFjaCBzaXRlLiBFcnJvciBiYXJzIHNob3cgbWluIGFuZCBtYXggb2YgZHVwbGljYXRlIGluY3ViYXRpb24gc2FtcGxlcy4gXmEpXiBEYXRhIHNob3duIGJ5IHNpdGUsIHdpdGhvdXQgbGl0dGVyIGRlcHRoLCBeYileIERhdGEgc2hvd24gYnkgZGVwdGggb2YgbGl0dGVyIGxheWVyLCBiaW5uZWQgYnkgY2xpbWF0ZSB6b25lLgoKYGBge3IgcGxvdC0xNGMtcHJvZmlsZS1meH0KcHJvLnBsb3QgPC0gZnVuY3Rpb24oZGYsIG1heERlcHRoLCBtaW4xNEMsIHJlcCkgewogIGdncGxvdChkZiwgYWVzKGQxNGMsIGx5cl9ib3QsIGNvbG9yID0gUE0sIHNoYXBlID0gRUNPLCBncm91cCA9IHJlcCkpICsKICAgIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDApICsKICAgIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDApICsKICAgIGdlb21fcG9pbnQoc2l6ZSA9IDMpICsKICAgIGdlb21fcGF0aCgpICsKICAgIHNjYWxlX3lfcmV2ZXJzZShsaW1pdHMgPSBjKG1heERlcHRoLCAwKSkgKwogICAgc2NhbGVfeF9jb250aW51b3VzKGxpbWl0cyA9IGMobWluMTRDLCAxODApKSArCiAgICBzY2FsZV9jb2xvcl9tYW51YWwobmFtZSA9ICJwYXJlbnQgbWF0ZXJpYWwiLAogICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIkFOIiA9ICJhbmRlc2l0ZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQlMiID0gImJhc2FsdCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiR1IiID0gImdyYW5pdGUiKSwKICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSBjKCJBTiIgPSAiYmx1ZSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkJTIiA9ICJyZWQiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJHUiIgPSAiZGFya2dyYXkiKSkgKwogICAgc2NhbGVfc2hhcGVfbWFudWFsKG5hbWUgPSAiZWNvc3lzdGVtIiwKICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCJwcCIgPSBleHByZXNzaW9uKGl0YWxpYygiUC4gcG9uZGVyb3NhIikpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInJmIiA9IGV4cHJlc3Npb24oaXRhbGljKCJBLiBtYWduaWZpY2EiKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAid2YiID0gZXhwcmVzc2lvbihpdGFsaWMoIkEuIGNvbmNvbG9yIikpKSwKICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSBjKCJwcCIgPSAxNSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicmYiID0gMTYsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIndmIiA9IDE3KSkgKwogICAgeGxhYihleHByZXNzaW9uKERlbHRhKicnXjE0KidDICjigLApJykpICsKICAgIHlsYWIoIkRlcHRoIChjbSkiKSArCiAgICB0aGVtZV9idygpICsKICAgIHRoZW1lKHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCkpCn0KYGBgCgpgYGB7ciBwbG90LTIwMDEtcHJvZmlsZXN9CiMgbGFwcGx5KHNyYS4yMDAxLmxzLCBmdW5jdGlvbihkZikgcHJvLnBsb3QoZGYsIG1heChkZiRseXJfYm90KSwgbWluKGRmJGQxNGMpLCBkZiRwcm9fcmVwKSkKYGBgCgpgYGB7ciBwbG90LTIwMTktcHJvZmlsZXN9CiMgbGFwcGx5KHNyYS4yMDE5LmxzLCBmdW5jdGlvbihkZikgcHJvLnBsb3QoZGYsIG1heChkZiRseXJfYm90KSwgbWluKGRmJGQxNGMpLCBkZiRwcm9fcmVwKSkKYGBgCgpgYGB7ciBwbG90LTIwMTktY28yLXByb2ZpbGVzfQojIGxhcHBseShzcmEuMjAxOS5pbmMubHMsIGZ1bmN0aW9uKGRmKSBwcm8ucGxvdChkZiwgbWF4KGRmJGx5cl9ib3QpLCBtaW4oZGYkZDE0YyksIE5BKSkKYGBgCgojIyAyMDAxIG1lYW4gcmFkaW9jYXJib24gcHJvZmlsZXMKYGBge3IgcGxvdC0yMDAxLWF2Zy1wcm9maWxlc30KIyBjb21iaW5lIHJlcHMKc3JhLjIwMDEuc3VtLmxzICA8LSBsYXBwbHkoc3JhLjIwMDEubHMsIGZ1bmN0aW9uKGRmKSB7CiAgZGYgPC0gZGF0YS5mcmFtZShkZiAlPiUKICAgICAgICAgICAgICAgICAgICAgZmlsdGVyKGx5cl9ib3QgPD0gNDApICU+JQogICAgICAgICAgICAgICAgICAgICBtdXRhdGUobHlyX3RvcF9jaCA9IGFzLmNoYXJhY3RlcihseXJfdG9wKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGx5cl9ib3RfY2ggPSBhcy5jaGFyYWN0ZXIobHlyX2JvdCkpICU+JQogICAgICAgICAgICAgICAgICAgICBzZWxlY3QoUE0sIEVDTywgUE1lY28sIGZtLCBkMTRjLCBseXJfdG9wX2NoLCBseXJfYm90X2NoKSAlPiUKICAgICAgICAgICAgICAgICAgICAgZ3JvdXBfYnkoUE0sIEVDTywgUE1lY28sIGx5cl90b3BfY2gsIGx5cl9ib3RfY2gpICU+JQogICAgICAgICAgICAgICAgICAgICBzdW1tYXJpemVfYWxsKGxpc3QobWVhbiA9IG1lYW4sIHNkID0gc2QpLCBuYS5ybSA9IFRSVUUpKQogIG5hbWVzKGRmKSA8LSBjKCJQTSIsICJFQ08iLCAiUE1lY28iLCAibHlyX3RvcCIsICJseXJfYm90IiwgImZtIiwgImQxNGMiLCAiZm1fc2QiLCAiZDE0Y19zZCIpCiAgZGYkbHlyX3RvcCA8LSBhcy5udW1lcmljKGRmJGx5cl90b3ApCiAgZGYkbHlyX2JvdCA8LSBhcy5udW1lcmljKGRmJGx5cl9ib3QpCiAgZGYkZDE0Y191IDwtIGRmJGQxNGMgKyBkZiRkMTRjX3NkCiAgZGYkZDE0Y19sIDwtIGRmJGQxNGMgLSBkZiRkMTRjX3NkCiAgcmV0dXJuKGRmW29yZGVyKGRmJGx5cl9ib3QpLCBdKQp9KQpzcmEuMDEuc3VtIDwtIGJpbmRfcm93cyhzcmEuMjAwMS5zdW0ubHMpICU+JQogIG11dGF0ZShlY28gPSBmYWN0b3IoaWZlbHNlKEVDTyA9PSAicHAiLCAid2FybSIsCiAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoRUNPID09ICJ3ZiIsICJjb29sIiwgImNvbGQiKSksCiAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSBjKCJ3YXJtIiwgImNvb2wiLCAiY29sZCIpKSwKICAgICAgICAgcG0gPSBpZmVsc2UoUE0gPT0gIkFOIiwgImFuZGVzaXRlIiwKICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKFBNID09ICJCUyIsICJiYXNhbHQiLCAiZ3Jhbml0ZSIpKSkKCiMgcGxvdApmaWcubiA8LSBmaWcubiArIDEKc3JhLjAxLnN1bSAlPiUKICBnZ3Bsb3QoLiwgYWVzKGQxNGMsIGx5cl9ib3QsIGNvbG9yID0gcG0sIHNoYXBlID0gZWNvLCBncm91cCA9IFBNZWNvKSkgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IGF0bS5kMTQuMjAwMSkgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDApICsKICBnZW9tX3BvaW50KHNpemUgPSAzKSArCiAgZ2VvbV9lcnJvcmJhcmgoCiAgICBhZXMoeG1pbiA9IGQxNGNfbCwgCiAgICAgICAgeG1heCA9IGQxNGNfdSwKICAgICAgICBjb2xvciA9IHBtKSwgCiAgICBoZWlnaHQgPSAxLjUpICsKICBnZW9tX3BhdGgoKSArCiAgc2NhbGVfeV9yZXZlcnNlKGxpbWl0cyA9IGMoNDAsIDApKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGxpbWl0cyA9IGMoLTEwMCwgMTgwKSkgKyAgICAKICBzY2FsZV9jb2xvcl9tYW51YWwobmFtZSA9ICJwYXJlbnQgbWF0ZXJpYWwiLAogICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSBjKCJhbmRlc2l0ZSIgPSAiYmx1ZSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJiYXNhbHQiID0gInJlZCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJncmFuaXRlIiA9ICJkYXJrZ3JheSIpKSArCiAgc2NhbGVfc2hhcGVfbWFudWFsKG5hbWUgPSAiZWNvc3lzdGVtIiwKICAgICAgICAgICAgICAgICAgICAgdmFsdWVzID0gYygid2FybSIgPSAxNSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImNvb2wiID0gMTYsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJjb2xkIiA9IDE3KSkgKwogIHhsYWIoZXhwcmVzc2lvbihEZWx0YSonJ14xNConQyAo4oCwKScpKSArCiAgeWxhYigiRGVwdGggKGNtKSIpICsKICBmYWNldF9ncmlkKHJvd3MgPSB2YXJzKGVjbyksIGNvbHMgPSB2YXJzKHBtKSkgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCkpCmBgYAo+KipGaWcuIGByIHtmaWcubn1gLiBNZWFuIHByb2ZpbGUgJFxEZWx0YSReMTReQyBmb3IgMjAwMSBzYW1wbGVzKioKCj4qQ2FwdGlvbjoqIE1lYW4gJFxEZWx0YSReMTReQyBieSBkZXB0aCBmb3IgZWFjaCBzaXRlIGluIDIwMDEuIEVycm9yIGJhcnMgc2hvdyDCsTEgc3RhbmRhcmQgZGV2aWF0aW9uLCBzb2xpZCB2ZXJ0aWNhbCBsaW5lIHNob3dzICRcRGVsdGEkXjE0XkMgb2YgdGhlIGF0bW9zcGhlcmUgaW4gdGhlIHllYXIgb2Ygc2FtcGxpbmcuCgojIyAyMDA5IHJhZGlvY2FyYm9uIHByb2ZpbGVzCmBgYHtyIGxvYWQtMjAwOS1kYXRhfQojIDIwMDkgc3VtbWFyeSBkYXRhIChmcm9tIEMuIFJhc211c3NlbikKcmFzMTguc3VtIDwtIHJlYWRfZXhjZWwoCiAgIi4uL2RhdGEvZXh0ZXJuYWwvc3JhX3Jhc19zdW0vc2llcnJhX2RhdGFfc3VtbWFyeV8yMDIwLnhsc3giLAogIHNoZWV0ID0gIkRhdGFfU3VtbWFyeV8yMDE4X3BhcGVyIikKCiMgcmVtb3ZlIGVtcHR5IGRhdGEgcm93cwpyYXMxOC5zdW0gPC0gcmFzMTguc3VtWy13aGljaChpcy5uYShyYXMxOC5zdW0kYFNhbXBsZSBJRGApKSwgXQoKIyBzdW1tYXJpemUgMDkgZGF0YQpzcmEuMDkuc3VtIDwtIHJhczE4LnN1bSAlPiUKICBtdXRhdGUoCiAgICBFQ08gPSBpZmVsc2UoQmlvbWUgPT0gIlBQIiwgInBwIiwgaWZlbHNlKEJpb21lID09ICJXRiIsICJ3ZiIsICJyZiIpKSwKICAgIFBNID0gaWZlbHNlKFBhcmVudF9NYXRlcmlhbCA9PSAiQW5kZXNpdGUiLCAiQU4iLCBpZmVsc2UoUGFyZW50X01hdGVyaWFsID09ICJCYXNhbHQiLCAiQlMiLCAiR1IiKSksCiAgICBlY28gPSBmYWN0b3IoaWZlbHNlKEVDTyA9PSAicHAiLCAid2FybSIsIGlmZWxzZShFQ08gPT0gIndmIiwgImNvb2wiLCAiY29sZCIpKSwKICAgICAgICAgICAgICAgICBsZXZlbHMgPSBjKCJ3YXJtIiwgImNvb2wiLCAiY29sZCIpKSwKICAgIHBtID0gcGFzdGUwKHRvbG93ZXIoc3Vic3RyKFBhcmVudF9NYXRlcmlhbCwgMSwgMSkpLCAKICAgICAgICAgICAgICAgIHN1YnN0cihQYXJlbnRfTWF0ZXJpYWwsIDIsIG5jaGFyKFBhcmVudF9NYXRlcmlhbCkpKSwKICAgIG1hc3Nfa2dtMiA9IEJEX2dfY21fMyAqIFNvaWxfZmluZWZyYWN0aW9uICogKGBib3R0b20gbWluZXJhbGAgLSBgdG9wIG1pbmVyYWxgKSAqIDEwKSAlPiUKICBtdXRhdGUoUE1lY28gPSBwYXN0ZTAoUE0sIEVDTykpICU+JQogIHJlbmFtZShkMTRjID0gIs6UMTRDIiwKICAgICAgICAgbHlyX2JvdCA9ICJib3R0b20gbWluZXJhbCIsCiAgICAgICAgIGx5cl90b3AgPSAidG9wIG1pbmVyYWwiKQpzcmEuMjAwOS5scyA8LSBsYXBwbHkoc3BsaXQoc3JhLjA5LnN1bSwgc3JhLjA5LnN1bSRQTWVjbyksIGZ1bmN0aW9uKGRmKSB7CiAgZGYkbHlyX2ZyYWN0aW9uX21vZGVybiA8LSBjYWxjX2ZtKGRmJGQxNGMsIDIwMDkpCiAgcmV0dXJuKGRhdGEuZnJhbWUoZGYpKQp9KQoKIyAyMDA5IGJ1bGsgQyBkYXRhCnJhczE4LmJsa0MgPC0gYXMuZGF0YS5mcmFtZShyZWFkX2V4Y2VsKAogICIuLi9kYXRhL2V4dGVybmFsL3NyYV9yYXNfc3VtL3NpZXJyYV9kYXRhX3N1bW1hcnlfMjAyMC54bHN4IiwKICBzaGVldCA9ICIyMDA5X2J1bGtfZGF0YSIpKQoKIyBBZGQgUE0sIEVDTywgbWFzc19rZ20yIHZhcnMKcmFzMTguYmxrQyRFQ08gPC0gaWZlbHNlKHJhczE4LmJsa0MkQmlvbWUgPT0gIlBQIiwgInBwIiwgaWZlbHNlKHJhczE4LmJsa0MkQmlvbWUgPT0gIlJGIiwgInJmIiwgIndmIikpCnJhczE4LmJsa0MkUE1lY28gPC0gcGFzdGUwKHJhczE4LmJsa0MkUE0sIHJhczE4LmJsa0MkRUNPKQpyYXMxOC5ibGtDJG1hc3Nfa2dtMiA8LSByYXMxOC5ibGtDJFRoaWNrbmVzc19jbSAqIHJhczE4LmJsa0MkQkRfZ19jbV8zICogcmFzMTguYmxrQyRTb2lsX2ZpbmVmcmFjdGlvbiAqIDEwCgojIENhbGN1bGF0ZSBTT0Mgc3RvY2tzCnJhczE4LmJsa0MkbHlyX3NvYyA8LSByYXMxOC5ibGtDJFRoaWNrbmVzc19jbSAqIHJhczE4LmJsa0MkQkRfZ19jbV8zICogcmFzMTguYmxrQyRTb2lsX2ZpbmVmcmFjdGlvbiAqIHJhczE4LmJsa0MkQ19wY3QgKiAxMF4tMQoKIyBDYWxjdWxhdGUgY210diBTT0Mgc3RvY2tzCnJhczE4LmJsa0MkbHlyX3NvY19jbXR2IDwtIHVubGlzdChsYXBwbHkoc3BsaXQocmFzMTguYmxrQywgcmFzMTguYmxrQyRwcm9fbmFtZSksIGZ1bmN0aW9uKHgpIHsKICB4JGx5cl9zb2NfY210diA8LSBOQQogIGZvciAoaSBpbiBzZXEobnJvdyh4KSkpIHsKICAgIGlmIChpID09IDEpIHsKICAgICAgeCRseXJfc29jX2NtdHZbaV0gPC0geCRseXJfc29jW2ldCiAgICB9IGVsc2UgewogICAgICB4JGx5cl9zb2NfY210dltpXSA8LSB4JGx5cl9zb2NbaV0gKyB4JGx5cl9zb2NfY210dltpIC0gMV0KICAgIH0KICB9CiAgcmV0dXJuKHgkbHlyX3NvY19jbXR2KQp9KSkKYGBgCgpgYGB7ciBlcnJvci1CRC1wcmVkfQojIExPT0NWIGZ1bmN0aW9uLCBmaXQgPSBsbSBtb2QKbG9vY3YgPC0gZnVuY3Rpb24gKGZpdCkgewogIGggPC0gbG0uaW5mbHVlbmNlKGZpdCkkaAogIG1lYW4oKHJlc2lkdWFscyhmaXQpIC8gKDEtaCkpXjIpCn0KCiMgdGVzdCBmdW5jdGlvbiBmb3IgcHJlZGljdGluZyBCRCBhcyBmdW5jdGlvbiBvZiBQTSwgRUNPLCBhbmQgQyBjb250ZW50CmJkLm1vZCA8LSBsbShCRF9nX2NtXzMgfiBQTSAqIEVDTyArIFBNICogQ19wY3QgKyBgYm90dG9tIG1pbmVyYWxgLCByYXMxOC5ibGtDKQpiZC5wcmVkIDwtIHByZWRpY3QubG0oYmQubW9kLCByYXMxOC5ibGtDLCBpbnRlcnZhbCA9ICJwcmVkaWN0IiwgcHJlZC52YXIgPSBsb29jdihiZC5tb2QpKQpiZC5lcnIuZGYgPC0gcmFzMTguYmxrQwpiZC5lcnIuZGYkQkRfcHJlZCA8LSBiZC5wcmVkWyAsIDFdCmJkLmVyci5kZiRCRF9sIDwtIGJkLnByZWRbICwgMl0KYmQuZXJyLmRmJEJEX3UgPC0gYmQucHJlZFsgLCAzXQoKIyBwbG90CmdncGxvdChiZC5lcnIuZGYsIGFlcyhCRF9nX2NtXzMsIEJEX3ByZWQpKSArCiAgZ2VvbV9yaWJib24oYWVzKHltaW4gPSBCRF9sLCB5bWF4ID0gQkRfdSksIGZpbGwgPSAibGlnaHRncmF5IikgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIGZvcm11bGEgPSB5IH4geCwgc2UgPSBGQUxTRSwgY29sb3IgPSAiYmxhY2siKSArCiAgZ2VvbV9wb2ludChhZXMoY29sb3IgPSBQTSwgc2hhcGUgPSBFQ08sIHNpemUgPSBgYm90dG9tIG1pbmVyYWxgLzEwKSkgKwogIHNjYWxlX2NvbG9yX21hbnVhbChuYW1lID0gIlBhcmVudCBtYXRlcmlhbCIsCiAgICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9IGMoIkFOIiA9IGFuZGVzaXRlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJCUyIgPSBiYXNhbHQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkdSIiA9IGdyYW5pdGUpKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUocGFuZWwuZ3JpZCA9IGVsZW1lbnRfYmxhbmsoKSkKYGBgCgpgYGB7ciBwbG90LTIwMDktMTRjLXByb2ZpbGVzfQojIHBsb3QKZmlnLm4gPC0gZmlnLm4gKyAxCnNyYS4wOS5zdW0gJT4lCiAgZ2dwbG90KC4sIGFlcyhkMTRjLCBseXJfYm90LCBjb2xvciA9IHBtLCBzaGFwZSA9IGVjbywgZ3JvdXAgPSBQTWVjbykpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBhdG0uZDE0LjIwMDkpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwKSArCiAgZ2VvbV9wb2ludChzaXplID0gMykgKwogIGdlb21fcGF0aChsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgc2NhbGVfeV9yZXZlcnNlKCkgKwogIHNjYWxlX3hfY29udGludW91cyhsaW1pdHMgPSBjKC0xMDAsIDE4MCkpICsgICAgCiAgc2NhbGVfY29sb3JfbWFudWFsKG5hbWUgPSAicGFyZW50IG1hdGVyaWFsIiwKICAgICAgICAgICAgICAgICAgICAgdmFsdWVzID0gYygiYW5kZXNpdGUiID0gImJsdWUiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiYmFzYWx0IiA9ICJyZWQiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiZ3Jhbml0ZSIgPSAiZGFya2dyYXkiKSkgKwogIHNjYWxlX3NoYXBlX21hbnVhbChuYW1lID0gImVjb3N5c3RlbSIsCiAgICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9IGMoIndhcm0iID0gMCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImNvb2wiID0gMSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImNvbGQiID0gMikpICsKICB4bGFiKGV4cHJlc3Npb24oRGVsdGEqJydeMTQqJ0MgKOKAsCknKSkgKwogIHlsYWIoIkRlcHRoIChjbSkiKSArCiAgZmFjZXRfZ3JpZChyb3dzID0gdmFycyhlY28pLCBjb2xzID0gdmFycyhwbSkpICsKICB0aGVtZV9idygpICsKICB0aGVtZShwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpKQpgYGAKPioqRmlnLiBgciB7ZmlnLm59YC4gUHJvZmlsZSAkXERlbHRhJF4xNF5DIGZvciAyMDA5IHNhbXBsZXMqKgoKPipDYXB0aW9uOiogUHJvZmlsZSAkXERlbHRhJF4xNF5DIGJ5IGRlcHRoIGZvciBlYWNoIHNpdGUgaW4gMjAwOS4gU29saWQgdmVydGljYWwgbGluZSBzaG93cyAkXERlbHRhJF4xNF5DIG9mIHRoZSBhdG1vc3BoZXJlIGluIHRoZSB5ZWFyIG9mIHNhbXBsaW5nLiBFcnJvciBiYXJzIG5vdCBzaG93biBhcyBvbmx5IGEgc2luZ2xlIHJlcGxpY2F0ZSBwcm9maWxlIHdhcyBhbmFseXplZCBwZXIgc2l0ZS4KCiMjIDIwMTkgbWVhbiByYWRpb2NhcmJvbiBwcm9maWxlcwpgYGB7ciBwbG90LTIwMTktYXZnLXByb2ZpbGVzfQojIGNvbWJpbmUgcmVwcwpzcmEuMjAxOS5zdW0ubHMgIDwtIGxhcHBseShzcmEuMjAxOS5scywgZnVuY3Rpb24oZGYpIHsKICBkZiA8LSBkYXRhLmZyYW1lKGRmICU+JQogICAgICAgICAgICAgICAgICAgICBtdXRhdGUobHlyX3RvcF9jaCA9IGFzLmNoYXJhY3RlcihseXJfdG9wKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGx5cl9ib3RfY2ggPSBhcy5jaGFyYWN0ZXIobHlyX2JvdCkpICU+JQogICAgICAgICAgICAgICAgICAgICBzZWxlY3QoUE0sIEVDTywgUE1lY28sIGZtLCBkMTRjLCBseXJfdG9wX2NoLCBseXJfYm90X2NoKSAlPiUKICAgICAgICAgICAgICAgICAgICAgZ3JvdXBfYnkoUE0sIEVDTywgUE1lY28sIGx5cl90b3BfY2gsIGx5cl9ib3RfY2gpICU+JQogICAgICAgICAgICAgICAgICAgICBzdW1tYXJpemVfYWxsKGxpc3QobWVhbiA9IG1lYW4sIHNkID0gc2QpLCBuYS5ybSA9IFRSVUUpKQogIG5hbWVzKGRmKSA8LSBjKCJQTSIsICJFQ08iLCAiUE1lY28iLCAibHlyX3RvcCIsICJseXJfYm90IiwgImZtIiwgImQxNGMiLCAiZm1fc2QiLCAiZDE0Y19zZCIpCiAgZGYkbHlyX3RvcCA8LSBhcy5udW1lcmljKGRmJGx5cl90b3ApCiAgZGYkbHlyX2JvdCA8LSBhcy5udW1lcmljKGRmJGx5cl9ib3QpCiAgZGYkZDE0Y191IDwtIGRmJGQxNGMgKyBkZiRkMTRjX3NkCiAgZGYkZDE0Y19sIDwtIGRmJGQxNGMgLSBkZiRkMTRjX3NkCiAgcmV0dXJuKGRmKQp9KQpzcmEuMTkuc3VtIDwtIGJpbmRfcm93cyhzcmEuMjAxOS5zdW0ubHMpICU+JQogIG11dGF0ZShlY28gPSBmYWN0b3IoaWZlbHNlKEVDTyA9PSAicHAiLCAid2FybSIsCiAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoRUNPID09ICJ3ZiIsICJjb29sIiwgImNvbGQiKSksCiAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSBjKCJ3YXJtIiwgImNvb2wiLCAiY29sZCIpKSwKICAgICAgICAgcG0gPSBpZmVsc2UoUE0gPT0gIkFOIiwgImFuZGVzaXRlIiwKICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKFBNID09ICJCUyIsICJiYXNhbHQiLCAiZ3Jhbml0ZSIpKSkgCgojIHBsb3QKZmlnLm4gPC0gZmlnLm4gKyAxCnNyYS4xOS5zdW0gJT4lCiAgZ2dwbG90KC4sIGFlcyhkMTRjLCBseXJfYm90LCBjb2xvciA9IHBtLCBzaGFwZSA9IGVjbywgZ3JvdXAgPSBQTWVjbykpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBhdG0uZDE0LjIwMTkpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwKSArCiAgZ2VvbV9wb2ludChzaXplID0gMi43KSArCiAgZ2VvbV9lcnJvcmJhcmgoCiAgICBhZXMoeG1pbiA9IGQxNGNfbCwgCiAgICAgICAgeG1heCA9IGQxNGNfdSwKICAgICAgICBjb2xvciA9IHBtKSwgCiAgICBoZWlnaHQgPSAxLjUpICsKICBnZW9tX3BhdGgoKSArCiAgc2NhbGVfeV9yZXZlcnNlKGxpbWl0cyA9IGMobWF4KHNyYS4xOS5zdW0kbHlyX2JvdCksIDApKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGxpbWl0cyA9IGMobWluKHNyYS4xOS5zdW0kZDE0YyksIDE4MCkpICsgICAgCiAgc2NhbGVfY29sb3JfbWFudWFsKG5hbWUgPSAicGFyZW50IG1hdGVyaWFsIiwKICAgICAgICAgICAgICAgICAgICAgdmFsdWVzID0gYygiYW5kZXNpdGUiID0gImJsdWUiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiYmFzYWx0IiA9ICJyZWQiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiZ3Jhbml0ZSIgPSAiZGFya2dyYXkiKSkgKwogIHNjYWxlX3NoYXBlX21hbnVhbChuYW1lID0gImVjb3N5c3RlbSIsCiAgICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9IGMoIndhcm0iID0gMTUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJjb29sIiA9IDE2LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiY29sZCIgPSAxNykpICsKICB4bGFiKGV4cHJlc3Npb24oRGVsdGEqJydeMTQqJ0MgKOKAsCknKSkgKwogIHlsYWIoIkRlcHRoIChjbSkiKSArCiAgZmFjZXRfZ3JpZChyb3dzID0gdmFycyhlY28pLCBjb2xzID0gdmFycyhwbSkpICsKICB0aGVtZV9idygpICsKICB0aGVtZShwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpKQpgYGAKPioqRmlnLiBgciB7ZmlnLm59YC4gTWVhbiBwcm9maWxlICRcRGVsdGEkXjE0XkMgZm9yIDIwMTkgc2FtcGxlcyoqCgo+KkNhcHRpb246KiBNZWFuICRcRGVsdGEkXjE0XkMgYnkgZGVwdGggZm9yIGVhY2ggc2l0ZSBpbiAyMDE5LiBFcnJvciBiYXJzIHNob3cgwrExIHN0YW5kYXJkIGRldmlhdGlvbiwgc29saWQgdmVydGljYWwgbGluZSBzaG93cyAkXERlbHRhJF4xNF5DIG9mIHRoZSBhdG1vc3BoZXJlIGluIHRoZSB5ZWFyIG9mIHNhbXBsaW5nLgoKIyMgQ2hhbmdlIGluICRcRGVsdGEkXjE0XkMgb3ZlciB0aW1lIGJldHdlZW4gMjAwMSBhbmQgMjAxOSAKCmBgYHtyIHBsb3QtYWxsLWF2Z30KIyBjb21iaW5lICcwMSBhbmQgJzE5IGRhdGEgZm9yIHBsb3R0aW5nCnNyYS4wMS5zdW0kWWVhciA8LSAyMDAxCnNyYS4xOS5zdW0kWWVhciA8LSAyMDE5CgpzcmEuMDEuMTkuc3VtIDwtIHJiaW5kKHNyYS4wMS5zdW0sIHNyYS4xOS5zdW0pCnNyYS4wMS4xOS5zdW0kWWVhciA8LSBhcy5mYWN0b3Ioc3JhLjAxLjE5LnN1bSRZZWFyKQoKZmlnLm4gPC0gZmlnLm4gKyAxCnNyYS4wMS4xOS5zdW0gJT4lCiAgbXV0YXRlKFBNZWNvX3llYXIgPSBwYXN0ZTAoUE1lY28sIFllYXIpLAogICAgICAgICBlY29ZZWFyID0gcGFzdGUwKEVDTywgWWVhciksCiAgICAgICAgIGVjb1llYXIyID0gaWZlbHNlKGVjb1llYXIgPT0gInBwMjAwMSIsICJ3YXJtICgyMDAxKSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShlY29ZZWFyID09ICJwcDIwMTkiLCAid2FybSAoMjAxOSkiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGVjb1llYXIgPT0gIndmMjAwMSIsICJjb29sICgyMDAxKSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGVjb1llYXIgPT0gIndmMjAxOSIsICJjb29sICgyMDE5KSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShlY29ZZWFyID09ICJyZjIwMDEiLCAiY29sZCAoMjAwMSkiLCAiY29sZCAoMjAxOSkiKSkpKSkpICU+JQogIGdncGxvdCguLCBhZXMoZDE0YywgbHlyX2JvdCwgY29sb3IgPSBwbSwgc2hhcGUgPSBlY29ZZWFyMiwgZ3JvdXAgPSBQTWVjb195ZWFyKSkgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IGF0bS5kMTQuMjAwMSkgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IGF0bS5kMTQuMjAxOSwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDApICsKICBnZW9tX3BvaW50KHNpemUgPSAzKSArCiAgZ2VvbV9lcnJvcmJhcmgoCiAgICBhZXMoeG1pbiA9IGQxNGNfbCwgCiAgICAgICAgeG1heCA9IGQxNGNfdSwKICAgICAgICBjb2xvciA9IHBtKSwgCiAgICBoZWlnaHQgPSAxLjUpICsKICBnZW9tX3BhdGgoYWVzKGxpbmV0eXBlID0gWWVhcikpICsKICBzY2FsZV95X3JldmVyc2UobGltaXRzID0gYyg0MSwgMCkpICsKICBzY2FsZV9jb2xvcl9tYW51YWwobmFtZSA9ICJwYXJlbnQgbWF0ZXJpYWwiLAogICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSBjKCJhbmRlc2l0ZSIgPSAiYmx1ZSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJiYXNhbHQiID0gInJlZCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJncmFuaXRlIiA9ICJkYXJrZ3JheSIpKSArCiAgc2NhbGVfc2hhcGVfbWFudWFsKG5hbWUgPSAiRWNvc3lzdGVtICh5ZWFyKSIsCiAgICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9IGMoIndhcm0gKDIwMDEpIiA9IDE1LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiY29vbCAoMjAwMSkiID0gMTYsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJjb2xkICgyMDAxKSIgPSAxNywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAid2FybSAoMjAxOSkiID0gMCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImNvb2wgKDIwMTkpIiA9IDEsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJjb2xkICgyMDE5KSIgPSAyKSkgKwogIHhsYWIoZXhwcmVzc2lvbihEZWx0YSonJ14xNConQyAo4oCwKScpKSArCiAgeWxhYigiRGVwdGggKGNtKSIpICsKICBmYWNldF9ncmlkKHJvd3MgPSB2YXJzKGVjbyksIGNvbHMgPSB2YXJzKHBtKSkgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCkpCmBgYAo+KipGaWcuIGByIHtmaWcubn1gLiBNZWFuIHByb2ZpbGUgJFxEZWx0YSReMTReQyBmb3IgMjAwMSBhbmQgMjAxOSBzYW1wbGVzKioKCj4qQ2FwdGlvbjoqIE1lYW4gJFxEZWx0YSReMTReQyBieSBkZXB0aCBmb3IgZWFjaCBzaXRlIGluIDIwMDEgYW5kIDIwMTkuIEVycm9yIGJhcnMgc2hvdyDCsTEgc3RhbmRhcmQgZGV2aWF0aW9uLiBWZXJ0aWNhbCBsaW5lcyBzaG93ICRcRGVsdGEkXjE0XkMgb2YgdGhlIGF0bW9zcGhlcmUgaW4gMjAwMSAoc29saWQpIGFuZCAyMDE5IChkYXNoZWQpLgoKIyMgSW5jdWJhdGlvbiAkXERlbHRhJF4xNF5DLUNPfjJ+CgpgYGB7ciBpbmMtZDE0Yy1wbG90LXNldHVwfQojIyAyMDE5CnNyYS4yMDE5LmluYy5kZiA8LSBiaW5kX3Jvd3Moc3JhLjIwMTkuaW5jLmxzKQojIGFkZCBsaXR0ZXIgaW5jIGRhdGEgYW5kIHN1bW1hcml6ZQpzcmEuMjAxOS5pbmMuc3VtLmRmIDwtIGRhdGEuZnJhbWUocmJpbmQoCiAgc3JhLjIwMTkuaW5jX0wuc3VtLAogIHNyYS4yMDE5LmluYy5kZiAlPiUKICAgIG11dGF0ZShlY28gPSBmYWN0b3IoaWZlbHNlKEVDTyA9PSAicHAiLCAid2FybSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKEVDTyA9PSAid2YiLCAiY29vbCIsICJjb2xkIikpLAogICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gYygid2FybSIsICJjb29sIiwgImNvbGQiKSksCiAgICAgICAgICAgcG0gPSBmYWN0b3IoaWZlbHNlKFBNID09ICJBTiIsICJhbmRlc2l0ZSIsCiAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShQTSA9PSAiQlMiLCAiYmFzYWx0IiwgImdyYW5pdGUiKSkpLAogICAgICAgICAgICMgcmVtb3ZlIEdScmYgMTAtMjAgImEiIHBvaW50CiAgICAgICAgICAgZDE0YyA9IHJlcGxhY2UoZDE0Yywgd2hpY2goZDE0YyA8IC0zMDApLCBOQSksCiAgICAgICAgICAgWWVhciA9IGZhY3RvcihZZWFyKSkgJT4lCiAgZ3JvdXBfYnkoWWVhciwgUE1lY28sIHBtLCBlY28sIGx5cl9ib3QsIGx5cl90b3ApICU+JQogIHN1bW1hcml6ZShkMTRjX21lYW4gPSBtZWFuKGQxNGMsIG5hLnJtID0gVFJVRSksCiAgICAgICAgICAgIGQxNGNfbCA9IG1pbihkMTRjLCBuYS5ybSA9IFRSVUUpLAogICAgICAgICAgICBkMTRjX3UgPSBtYXgoZDE0YywgbmEucm0gPSBUUlVFKSwKICAgICAgICAgICAgZm1fbWVhbiA9IG1lYW4oZm0pLAogICAgICAgICAgICBmbV9sID0gbWluKGZtKSwKICAgICAgICAgICAgZm1fdSA9IG1heChmbSkpKSkKc3JhLjIwMTkuaW5jLnN1bS5scyA8LSBzcGxpdChzcmEuMjAxOS5pbmMuc3VtLmRmLCBzcmEuMjAxOS5pbmMuc3VtLmRmJFBNZWNvKQoKIyAyMDAxCnNyYS4yMDAxLmluYy5kZiA8LSBiaW5kX3Jvd3Moc3JhLjIwMDEuaW5jLmxzKQpzcmEuMjAwMS5pbmMuc3VtLmRmIDwtIGRhdGEuZnJhbWUoCiAgc3JhLjIwMDEuaW5jLmRmICU+JQogICAgbXV0YXRlKGVjbyA9IGZhY3RvcihpZmVsc2UoRUNPID09ICJwcCIsICJ3YXJtIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShFQ08gPT0gIndmIiwgImNvb2wiLCAiY29sZCIpKSwKICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gYygid2FybSIsICJjb29sIiwgImNvbGQiKSksCiAgICAgICAgICAgcG0gPSBmYWN0b3IoaWZlbHNlKFBNID09ICJBTiIsICJhbmRlc2l0ZSIsCiAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKFBNID09ICJCUyIsICJiYXNhbHQiLCAiZ3Jhbml0ZSIpKSksCiAgICAgICAgICAgWWVhciA9IGZhY3RvcihZZWFyKSkgJT4lCiAgICBncm91cF9ieShZZWFyLCBQTWVjbywgcG0sIGVjbywgbHlyX2JvdCwgbHlyX3RvcCkgJT4lCiAgICBzdW1tYXJpemUoZDE0Y19tZWFuID0gbWVhbihkMTRjKSwKICAgICAgICAgICAgICBkMTRjX2wgPSBtaW4oZDE0YyksCiAgICAgICAgICAgICAgZDE0Y191ID0gbWF4KGQxNGMpLAogICAgICAgICAgICAgIGZtX21lYW4gPSBtZWFuKGZtKSwKICAgICAgICAgICAgICBmbV9sID0gbWluKGZtKSwKICAgICAgICAgICAgICBmbV91ID0gbWF4KGZtKSkKKQpzcmEuMjAwMS5pbmMuc3VtLmxzIDwtIHNwbGl0KHNyYS4yMDAxLmluYy5zdW0uZGYsIHNyYS4yMDAxLmluYy5zdW0uZGYkUE1lY28pCnNyYS4yMDAxLmluYy5zdW0uZGYgPC0gc3JhLjIwMDEuaW5jLnN1bS5kZlsgLCAhKG5hbWVzKHNyYS4yMDAxLmluYy5zdW0uZGYpICVpbiUgYygiZm1fbWVhbiIsICJmbV9sIiwgImZtX3UiLCAibHlyX3RvcCIsICJQTWVjbyIpKV0KYGBgCgpgYGB7ciBwbG90LWluYy1kMTRjLTIwMTl9CiMgMjAxOQpmaWcubiA8LSBmaWcubiArIDEKc3JhLjIwMTkuaW5jLnN1bS5kZltvcmRlcihzcmEuMjAxOS5pbmMuc3VtLmRmJGx5cl9ib3QpLCBdICU+JQogIGdncGxvdCguLCBhZXMoZDE0Y19tZWFuLCBseXJfYm90LCBjb2xvciA9IHBtLCBzaGFwZSA9IGVjbykpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBhdG0uZDE0LjIwMTksIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwKSArCiAgZ2VvbV9wb2ludChzaXplID0gMykgKwogIGdlb21fZXJyb3JiYXJoKAogICAgYWVzKHhtaW4gPSBkMTRjX2wsCiAgICAgICAgeG1heCA9IGQxNGNfdSwKICAgICAgICBjb2xvciA9IHBtKSwKICAgIGhlaWdodCA9IDEuNSkgKwogIGdlb21fcGF0aChsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgc2NhbGVfeV9yZXZlcnNlKCkgKwogIHNjYWxlX2NvbG9yX21hbnVhbChuYW1lID0gIlBhcmVudCBtYXRlcmlhbCIsCiAgICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9IGMoImFuZGVzaXRlIiA9ICJibHVlIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImJhc2FsdCIgPSAicmVkIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImdyYW5pdGUiID0gImRhcmtncmF5IikpICsKICBzY2FsZV9zaGFwZV9tYW51YWwobmFtZSA9ICJFY29zeXN0ZW0iLAogICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSBjKCJ3YXJtIiA9IDAsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJjb29sIiA9IDEsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJjb2xkIiA9IDIpKSArCiAgeGxhYihleHByZXNzaW9uKCdJbmN1YmF0aW9uICcqRGVsdGEqJydeMTQqJ0MtQ08nWzJdKicgKOKAsCknKSkgKwogIHlsYWIoIkRlcHRoIChjbSkiKSArCiAgZmFjZXRfZ3JpZChyb3dzID0gdmFycyhlY28pKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUocGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSkKYGBgCj4qKkZpZy4gYHIge2ZpZy5ufWAuICRcRGVsdGEkXjE0XkMtQ09+Mn4gb2YgMjAxOSBidWxrIHNvaWwgaW5jdWJhdGlvbnMqKgoKPipDYXB0aW9uOiogJFxEZWx0YSReMTReQ09+Mn4gYnkgZGVwdGggZm9yIGVhY2ggc2l0ZSBpbiAyMDE5LiBPbmUgcmVwIGZyb20gR1JyZiAxMC0yMCAodGhlIDEwLTIwIGNtIGluY3JlbWVudCBzYW1wbGUgZnJvbSB0aGUgY29sZCBncmFuaXRlIHNpdGUpIGlzIHN0cm9uZ2x5IGRlcGxldGVkIHJlbGF0aXZlIHRvIHRoZSBvdGhlciByZXA6ICRcRGVsdGEkXjE0XkMtQ09+Mn4gPSBgciB7c3JhLjIwMTkuaW5jLmRmW3NyYS4yMDE5LmluYy5kZiRQTWVjbyA9PSAiR1JyZiIgJiBzcmEuMjAxOS5pbmMuZGYkbHlyX2JvdCA9PSAyMCwgImQxNGMiXX1gLiBUaGUgaGlnaGx5IGRlcGxldGVkIHNhbXBsZSBoYXMgYmVlbiBleGNsdWRlZCBmb3IgZGlzcGxheSByZWFzb25zLgoKYGBge3IgcGxvdC1pbmMtZDE0Yy0yMDAxfQojIHBsb3QgMjAwMSBkYXRhCmZpZy5uIDwtIGZpZy5uICsgMQpzcmEuMjAwMS5pbmMuc3VtLmRmICU+JQogIGdncGxvdCguLCBhZXMoZDE0Y19tZWFuLCBseXJfYm90LCBjb2xvciA9IHBtLCBzaGFwZSA9IGVjbykpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBhdG0uZDE0LjIwMDEpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwKSArCiAgZ2VvbV9wb2ludChzaXplID0gMykgKwogIGdlb21fZXJyb3JiYXJoKAogICAgYWVzKHhtaW4gPSBkMTRjX2wsCiAgICAgICAgeG1heCA9IGQxNGNfdSwKICAgICAgICBjb2xvciA9IHBtKSwKICAgIGhlaWdodCA9IDEuNSkgKwogIGdlb21fcGF0aCgpICsKICBzY2FsZV95X3JldmVyc2UoKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKG5hbWUgPSAiUGFyZW50IG1hdGVyaWFsIiwKICAgICAgICAgICAgICAgICAgICAgdmFsdWVzID0gYygiYW5kZXNpdGUiID0gImJsdWUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJiYXNhbHQiID0gInJlZCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImdyYW5pdGUiID0gImRhcmtncmF5IikpICsKICBzY2FsZV9zaGFwZV9tYW51YWwobmFtZSA9ICJFY29zeXN0ZW0iLAogICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSBjKCJ3YXJtIiA9IDE1LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJjb29sIiA9IDE2LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJjb2xkIiA9IDE3KSkgKwogIHNjYWxlX3hfY29udGludW91cyhsaW1pdHMgPSBjKC03MCwgMTkwKSkgKwogIHhsYWIoZXhwcmVzc2lvbignSW5jdWJhdGlvbiAnKkRlbHRhKicnXjE0KidDLUNPJ1syXSonICjigLApJykpICsKICB5bGFiKCJEZXB0aCAoY20pIikgKwogIGZhY2V0X2dyaWQocm93cyA9IHZhcnMoZWNvKSkgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCkpCmBgYAo+KipGaWcuIGByIHtmaWcubn1gLiAkXERlbHRhJF4xNF5DLUNPfjJ+IG9mIDIwMDEgYnVsayBzb2lsIGluY3ViYXRpb25zKioKCj4qQ2FwdGlvbjoqICRcRGVsdGEkXjE0XkNPfjJ+IGJ5IGRlcHRoIGZvciBlYWNoIHNpdGUgaW4gMjAwMS4gTm90ZSB0aGF0IHNvbWUgc2l0ZXMgb25seSBoYXZlIHR3byBkZXB0aCBpbmNyZW1lbnRzLiBTaW1pbGFyIHRvIHRoZSAyMDE5IGRhdGFzZXQsIG9uZSBvZiB0aGUgR1JyZiByZXBzIGZyb20gdGhlIGRlZXBlc3QgZGVwdGggaW5jcmVtZW50IHdhcyBzdHJvbmdseSBkZXBsZXRlZDogJFxEZWx0YSReMTReQy1DT34yfiA9IGByIHtzcmEuMjAwMS5pbmMuc3VtLmRmICU+JSBmaWx0ZXIocG0gPT0gImdyYW5pdGUiLCBlY28gPT0gImNvbGQiLCBseXJfYm90ID09IDI3KSAlPiUgcHVsbCgiZDE0Y19sIiwgImQxNGNfdSIpfWAuIEJvdGggcG9pbnRzIGhhdmUgYmVlbiBleGNsdWRlZCBmb3IgZGlzcGxheSByZWFzb25zLgoKYGBge3IgcGxvdC1pbmMtZDE0Yy1hbGx9CiMgcGxvdCB0b2dldGhlcgpzcmEuaW5jLmFsbCA8LSByYmluZChzcmEuMjAwMS5pbmMuc3VtLmRmLCAKICAgICAgICAgICAgICAgICAgICAgc3JhLjIwMTkuaW5jLnN1bS5kZlsgLCBuYW1lcyhzcmEuMjAxOS5pbmMuc3VtLmRmKSAlaW4lIG5hbWVzKHNyYS4yMDAxLmluYy5zdW0uZGYpXSkKc2F2ZShzcmEuaW5jLmFsbCwgZmlsZSA9ICJzcmEuaW5jLmFsbC5SRGF0YSIpCgpmaWcubiA8LSBmaWcubiArIDEgCnNyYS5pbmMuYWxsICU+JQogIGZpbHRlcihseXJfYm90ID4gMCkgJT4lCiAgbXV0YXRlKFBNZWNvX3llYXIgPSBwYXN0ZTAocG0sIGVjbywgWWVhciksCiAgICAgICAgIGVjb1llYXIgPSBwYXN0ZTAoZWNvLCAiICgiLCBZZWFyLCAiKSIpKSAlPiUKICBnZ3Bsb3QoLiwgYWVzKGQxNGNfbWVhbiwgbHlyX2JvdCwgY29sb3IgPSBwbSwgc2hhcGUgPSBlY29ZZWFyLCBncm91cCA9IFBNZWNvX3llYXIpKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gYXRtLmQxNC4yMDAxKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gYXRtLmQxNC4yMDE5LCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCkgKwogIGdlb21fcG9pbnQoc2l6ZSA9IDMpICsKICBnZW9tX2Vycm9yYmFyaCgKICAgIGFlcyh4bWluID0gZDE0Y19sLCAKICAgICAgICB4bWF4ID0gZDE0Y191LAogICAgICAgIGNvbG9yID0gcG0pLCAKICAgIGhlaWdodCA9IDEuNSkgKwogIGdlb21fcGF0aChhZXMobGluZXR5cGUgPSBZZWFyKSkgKwogIHNjYWxlX3lfcmV2ZXJzZShsaW1pdHMgPSBjKDQxLCAwKSkgKwogIHNjYWxlX2NvbG9yX21hbnVhbChuYW1lID0gInBhcmVudCBtYXRlcmlhbCIsCiAgICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9IGMoImFuZGVzaXRlIiA9ICJibHVlIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImJhc2FsdCIgPSAicmVkIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImdyYW5pdGUiID0gImRhcmtncmF5IikpICsKICBzY2FsZV9zaGFwZV9tYW51YWwobmFtZSA9ICJFY29zeXN0ZW0gKHllYXIpIiwKICAgICAgICAgICAgICAgICAgICAgdmFsdWVzID0gYygid2FybSAoMjAwMSkiID0gMTUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJjb29sICgyMDAxKSIgPSAxNiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImNvbGQgKDIwMDEpIiA9IDE3LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJ3YXJtICgyMDE5KSIgPSAwLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiY29vbCAoMjAxOSkiID0gMSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImNvbGQgKDIwMTkpIiA9IDIpKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGxpbWl0cyA9IGMoLTcwLCAxOTApKSArCiAgeGxhYihleHByZXNzaW9uKERlbHRhKicnXjE0KidDICjigLApJykpICsKICB5bGFiKCJEZXB0aCAoY20pIikgKwogIGZhY2V0X2dyaWQocm93cyA9IHZhcnMoZWNvKSwgY29scyA9IHZhcnMocG0pKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUocGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSkKYGBgCj4qKkZpZy4gYHIge2ZpZy5ufWAuICRcRGVsdGEkXjE0XkMtQ09+Mn4gb2YgMjAwMSBhbmQgMjAxOSBidWxrIHNvaWwgaW5jdWJhdGlvbnMqKgoKPipDYXB0aW9uOiogJFxEZWx0YSReMTReQ09+Mn4gYnkgZGVwdGggZm9yIGVhY2ggc2l0ZSBpbiAyMDAxIGFuZCAyMDE5LiBEaWZmZXJlbnQgZGVwdGggaW5jcmVtZW50cyB3ZXJlIHNhbXBsZWQgaW4gMjAwMSBhbmQgMjAxOS4gUG9pbnRzIGFyZSB0aGUgbWVhbiBvZiBsYWJvcmF0b3J5IGR1cGxpY2F0ZXM7IGVycm9yIGJhcnMgYXJlIHRoZSBtZWFzdXJlZCB2YWx1ZXMgb2YgZWFjaCBkdXBsaWNhdGUuIEdyYW5pdGUvY29sZCBwb2ludCBleGxjdWRlZCBmb3IgZGlzcGxheSByZWFzb25zIGFzIGl0IGlzIHN0cm9uZ2x5IGRlcGxldGVkLgoKIyMgSW5jdWJhdGlvbiB2cy4gYnVsayBzb2lsICRcRGVsdGEkXjE0XkMKCmBgYHtyIGluYy1idWxrLWQxNGMtcGxvdC1zZXR1cH0KIyBiaW5kIHJvd3Mgb2YgaW5jIGxpc3QKc3JhLjE5LmluYyA8LSBzcmEuMjAxOS5pbmMuc3VtLmRmCnNyYS4xOS5pbmMkVHlwZSA8LSAiaW5jIgoKIyAyMDAxCnNyYS4wMS5pbmMgPC0gc3JhLjIwMDEuaW5jLnN1bS5kZgpzcmEuMDEuaW5jJFR5cGUgPC0gImluYyIKCiMgcmJpbmQgYnVsayBkYXRhCnNyYS4xOS5idWxrIDwtIHNyYS4xOS5zdW1bd2hpY2goc3JhLjE5LnN1bSRseXJfYm90IDwgMzEpLCBjKCJZZWFyIiwgIlBNIiwgIkVDTyIsICJseXJfYm90IiwiZDE0YyIsICJkMTRjX2wiLCAiZDE0Y191IildCm5hbWVzKHNyYS4xOS5idWxrKVt3aGljaChuYW1lcyhzcmEuMTkuYnVsaykgPT0gImQxNGMiKV0gPC0gImQxNGNfbWVhbiIKc3JhLjE5LmJ1bGskVHlwZSA8LSAiYnVsayIKc3JhLjE5LmJ1bGsgPC0gc3JhLjE5LmJ1bGsgJT4lCiAgbXV0YXRlKHBtID0gZmFjdG9yKGlmZWxzZShQTSA9PSAiQU4iLCAiYW5kZXNpdGUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKFBNID09ICJCUyIsICJiYXNhbHQiLCAiZ3Jhbml0ZSIpKSksCiAgICAgICAgIGVjbyA9IGZhY3RvcihpZmVsc2UoRUNPID09ICJwcCIsICJ3YXJtIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoRUNPID09ICJ3ZiIsICJjb29sIiwgImNvbGQiKSksCiAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSBjKCJ3YXJtIiwgImNvb2wiLCAiY29sZCIpKSwKICAgICAgICAgUE0gPSBOVUxMLAogICAgICAgICBFQ08gPSBOVUxMKQpzcmEuMTkuaW5jLmJsayA8LSByYmluZChzcmEuMTkuYnVsaywgc3JhLjE5LmluY1sgLCBuYW1lcyhzcmEuMTkuaW5jKSAlaW4lIG5hbWVzKHNyYS4xOS5idWxrKV0pCnNhdmUoc3JhLjE5LmluYy5ibGssIGZpbGUgPSAic3JhLjE5LmluYy5ibGsuUkRhdGEiKQoKIyAyMDAxCiMgTmVlZCB0byBjYWxjdWxhdGUgd2VpZ2h0ZWQgYXZlcmFnZSBvZiByYWRpb2NhcmJvbiB2YWx1ZXMgYW5kIHN0b2NrcyBmb3IgY29tYmluZWQgaW5jIGRlcHRocyAKIyAxKSBhZGQgU09DIHN0b2NrcyB0byBkdXBsaWNhdGUgc3JhLjIwMDEubHMgb2JqCnNyYS4yMDAxLmxzMiA8LSBzcmEuMjAwMS5scwpmb3IoaSBpbiBzZXFfYWxvbmcoc3JhLjIwMDEubHMyKSkgewogIGl4IDwtIG1hdGNoKHNyYS4yMDAxLmxzMltbaV1dW1siSUQiXV0sIHNvYy4yMDAxLmxzW1tpXV1bWyJJRCJdXSkKICBzcmEuMjAwMS5sczJbW2ldXVsibHlyX3NvY19rZ20yIl0gPC0gc29jLjIwMDEubHNbW2ldXVtpeCwgImx5cl9zb2Nfa2dtMiJdCn0KIyAyKSB3ZWlnaHRlZCBhdmVyYWdlIGZ4CmQxZDIuMTRjLmZ4IDwtIGZ1bmN0aW9uKGRmKSB7CiAgc3VtX3NvYyA8LSBzdW0oZGZbMToyLCAibHlyX3NvY19rZ20yIl0pCiAgd3QxIDwtIGRmJGx5cl9zb2Nfa2dtMlsxXSAvIHN1bV9zb2MKICB3dDIgPC0gZGYkbHlyX3NvY19rZ20yWzJdIC8gc3VtX3NvYwogIGQxZDIgPC0gZGZbMSwgXQogIGQxZDIkSUQgPSBwYXN0ZShkZiRQTWVjb1sxXSwgZGYkcHJvX3JlcFsxXSwgZGYkbHlyX3RvcFsxXSwgZGYkbHlyX2JvdFsyXSwgc2VwID0gIl8iKQogIGQxZDIkbHlyX3NvY19rZ20yID0gc3VtKGRmJGx5cl9zb2Nfa2dtMlsxXSwgZGYkbHlyX3NvY19rZ20yWzJdKQogIGQxZDIkbHlyX2JvdCA9IGRmJGx5cl9ib3RbMl0KICBkMWQyJGZtIDwtIHN1bShkZiRmbVsxXSAqIHd0MSwgZGYkZm1bMl0gKiB3dDIpCiAgZDFkMiRkMTRjIDwtIHN1bShkZiRkMTRjWzFdICogd3QxLCBkZiRkMTRjWzJdICogd3QyKQogIHJldHVybihyYmluZChkMWQyLAogICAgICAgICAgICAgICBkZlszOm5yb3coZGYpLCBdKSkKfQojIDMpIGNhbGMuIHd0ZC4gYXZlcmFnZSBmb3IgR1JyZgpzcmEuMjAwMS5sczIkR1JyZiA8LSBiaW5kX3Jvd3MoCiAgbGFwcGx5KHNwbGl0KHNyYS4yMDAxLmxzMiRHUnJmLCBzcmEuMjAwMS5sczIkR1JyZiRwcm9fcmVwKSwgZnVuY3Rpb24oeCkgewogICAgZDFkMi4xNGMuZngoeCkKICB9KQopCiMgNCkgY2FsYy4gd3RkLiBhdmVyYWdlIGZvciBCU3JmCiMgICAgLSBwcm9ibGVtIGhlcmUgaXMgdGhhdCBvbmx5IG9uZSBwcm9fcmVwIGhhcyAwLTMgY20gZGF0YQojICAgIC0gc28sIG5lZWQgdG8gY2FsY3VsYXRlIHdlaWdodGVkIFNPQywgdGhlbiBjYWxjdWxhdGUgd2VpZ2h0ZWQgMTRDCiMgICAgLSBjb21wb3NpdGUgMC04ID0gMTVnIEJTcmZfMV8wLTMgKyA1IGcgZnJvbSBlYWNoIHByb19yZXAgQlNyZl8zLTgKQlNyZl9jb21wXzAxX2kgPC0gc3JhLjIwMDEubHMyJEJTcmZbd2hpY2goc3JhLjIwMDEubHMyJEJTcmYkbHlyX2JvdCA8IDkpLCBdCkJTcmZfY29tcF8wMV9pJHNvY193dCA8LSBjKDE1IC8gMzAsIHJlcCg1IC8gMzAsIDMpKQpCU3JmX2NvbXBfMDFfaSRzb2Nfd3RkIDwtIEJTcmZfY29tcF8wMV9pJGx5cl9zb2Nfa2dtMiAqIEJTcmZfY29tcF8wMV9pJHNvY193dAoKIyBjcmVhdGUgc3VtbWFyaXplZCBsaXN0CnNyYS4yMDAxLnN1bS5sczIgIDwtIGxhcHBseShzcmEuMjAwMS5sczIsIGZ1bmN0aW9uKGRmKSB7CiAgZGF0YS5mcmFtZSgKICAgIGRmICU+JQogICAgICBmaWx0ZXIobHlyX2JvdCA8PSA0MCkgJT4lCiAgICAgIG11dGF0ZShseXJfYm90X2NoID0gYXMuY2hhcmFjdGVyKGx5cl9ib3QpKSAlPiUKICAgICAgc2VsZWN0KFBNZWNvLCBkMTRjLCBmbSwgbHlyX2JvdF9jaCwgbHlyX3NvY19rZ20yKSAlPiUKICAgICAgZ3JvdXBfYnkoUE1lY28sIGx5cl9ib3RfY2gpICU+JQogICAgICBzdW1tYXJpemUoCiAgICAgICAgYWNyb3NzKHdoZXJlKGlzLm51bWVyaWMpLCBsaXN0KG1lYW4gPSBtZWFuLCBzZCA9IHNkKSwgbmEucm0gPSBUUlVFKSkgJT4lCiAgICAgIG11dGF0ZShseXJfYm90ID0gYXMubnVtZXJpYyhseXJfYm90X2NoKSkgJT4lCiAgICAgIHNlbGVjdCgtbHlyX2JvdF9jaCkKICApCn0pCgojIHJlbW92ZSBCU3JmIHJvdyB3LyBseXJfYm90ID0gMwpzcmEuMjAwMS5zdW0ubHMyJEJTcmYgPC0gc3JhLjIwMDEuc3VtLmxzMiRCU3JmWy13aGljaChzcmEuMjAwMS5zdW0ubHMyJEJTcmYkbHlyX2JvdCA9PSAzKSwgXQojIGNhbGN1bGF0ZSB3ZWlnaHRlZCBhdmVyYWdlIGZvciBkMTRjLCBmbSwgbHlyX3NvY19rZ20yCnNyYS4yMDAxLnN1bS5sczIkQlNyZlt3aGljaChzcmEuMjAwMS5zdW0ubHMyJEJTcmYkbHlyX2JvdCA9PSA4KSwgImQxNGNfbWVhbiJdIDwtIHN1bShCU3JmX2NvbXBfMDFfaSRkMTRjICogKEJTcmZfY29tcF8wMV9pJHNvY193dGQgLyBzdW0oQlNyZl9jb21wXzAxX2kkc29jX3d0ZCkpKQpzcmEuMjAwMS5zdW0ubHMyJEJTcmZbd2hpY2goc3JhLjIwMDEuc3VtLmxzMiRCU3JmJGx5cl9ib3QgPT0gOCksICJmbV9tZWFuIl0gPC0gc3VtKEJTcmZfY29tcF8wMV9pJGZtICogKEJTcmZfY29tcF8wMV9pJHNvY193dGQgLyBzdW0oQlNyZl9jb21wXzAxX2kkc29jX3d0ZCkpKQpzcmEuMjAwMS5zdW0ubHMyJEJTcmZbd2hpY2goc3JhLjIwMDEuc3VtLmxzMiRCU3JmJGx5cl9ib3QgPT0gOCksICJseXJfc29jX2tnbTJfbWVhbiJdIDwtIHN1bShCU3JmX2NvbXBfMDFfaSRzb2Nfd3RkKQpzcmEuMjAwMS5zdW0ubHMyJEJTcmZbd2hpY2goc3JhLjIwMDEuc3VtLmxzMiRCU3JmJGx5cl9ib3QgPT0gOCksIGMoImQxNGNfc2QiLCAiZm1fc2QiLCAibHlyX3NvY19rZ20yX3NkIildIDwtIE5BCgojIGNhbGN1bGF0ZSBjbXR2IHNvYwpzcmEuMjAwMS5zdW0ubHMyIDwtIGxhcHBseShzcmEuMjAwMS5zdW0ubHMyLCBmdW5jdGlvbih4KSB7CiAgeCA8LSB4W29yZGVyKHgkbHlyX2JvdCksIF0KICB4JGx5cl9zb2NfY210diA8LSBOQQogIGZvcihpIGluIHNlcV9hbG9uZyh4JGx5cl9ib3QpKSB7CiAgICAgIGlmKGkgPT0gMSkgewogICAgICAgIHgkbHlyX3NvY19jbXR2W2ldIDwtIHgkbHlyX3NvY19rZ20yX21lYW5baV0KICAgICAgfSBlbHNlIHsKICAgICAgICB4JGx5cl9zb2NfY210dltpXSA8LSB4JGx5cl9zb2Nfa2dtMl9tZWFuW2ldICsgeCRseXJfc29jX2NtdHZbaS0xXSAKICAgICAgfQogIH0KICByZXR1cm4oeCkKfSkKCiMgbWFrZSBkZgpzcmEuMDEuc3VtIDwtIGRhdGEuZnJhbWUoYmluZF9yb3dzKAogIGxhcHBseShzcmEuMjAwMS5zdW0ubHMyLCBmdW5jdGlvbihkZikgewogICAgZGYgJT4lCiAgICAgIG11dGF0ZShlY28gPSBmYWN0b3IoaWZlbHNlKGdyZXBsKCJwcCIsIGRmJFBNZWNvKSwgIndhcm0iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZ3JlcGwoIndmIiwgZGYkUE1lY28pLCAiY29vbCIsICJjb2xkIikpLAogICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoIndhcm0iLCAiY29vbCIsICJjb2xkIikpLAogICAgICAgICAgICAgcG0gPSBpZmVsc2UoZ3JlcGwoIkFOIiwgZGYkUE1lY28pLCAiYW5kZXNpdGUiLAogICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGdyZXBsKCJCUyIsIGRmJFBNZWNvKSwgImJhc2FsdCIsICJncmFuaXRlIikpLAogICAgICAgICAgICAgZDE0Y191ID0gZDE0Y19tZWFuICsgZDE0Y19zZCwKICAgICAgICAgICAgIGQxNGNfbCA9IGQxNGNfbWVhbiAtIGQxNGNfc2QsCiAgICAgICAgICAgICBZZWFyID0gMjAwMSwKICAgICAgICAgICAgIFR5cGUgPSAiYnVsayIpICU+JQogICAgICBzZWxlY3QobmFtZXMoc3JhLjAxLmluYykpICU+JQogICAgICBhcnJhbmdlKGx5cl9ib3QpCiAgfSkKKSkKIyBiaW5kIHdpdGggaW5jCnNyYS4wMS5pbmMuYmxrIDwtIHJiaW5kKGRhdGEuZnJhbWUoc3JhLjAxLmluYyksIHNyYS4wMS5zdW0pCnNhdmUoc3JhLjAxLmluYy5ibGssIGZpbGUgPSAic3JhLjAxLmluYy5ibGsuUkRhdGEiKQpgYGAKCmBgYHtyIHJlYWQtcmVzcC10c30KIyMgcmVhZCBpbiB0aW1lc2VyaWVzIG9mIENPMiByZWxlYXNlIGZyb20gaW5jdWJhdGlvbnMKIyAyMDE5CnNyYS4xOWEuY28yLnRzIDwtIHJlYWQuY3N2KCIuLi9kYXRhL2Rlcml2ZWQvbGFiX2plbmFfQ08yLXRpbWVzZXJpZXMvUzE5YV9DTzJfZmx1eF8yMDIxLTAxLTE5LmNzdiIpCnNyYS4xOWIuY28yLnRzIDwtIHJlYWQuY3N2KCIuLi9kYXRhL2Rlcml2ZWQvbGFiX2plbmFfQ08yLXRpbWVzZXJpZXMvUzE5Yl9DTzJfZmx1eF8yMDIxLTAxLTE5LmNzdiIpCgojIDIwMDEKc3JhLjAxLjEuY28yLnRzIDwtIHJlYWQuY3N2KCIuLi9kYXRhL2Rlcml2ZWQvbGFiX2plbmFfQ08yLXRpbWVzZXJpZXMvUzAxXzFfQ08yX2ZsdXhfMjAyMS0wMS0yNy5jc3YiKQpzcmEuMDEuMi5jbzIudHMgPC0gcmVhZC5jc3YoIi4uL2RhdGEvZGVyaXZlZC9sYWJfamVuYV9DTzItdGltZXNlcmllcy9TMDFfMl9DTzJfZmx1eF8yMDIxLTAxLTI3LmNzdiIpCgojIyBUZXN0IHRoYXQgcmVxdWlyZWQgbmFtZXMgYXJlIHByZXNlbnQKbm1zIDwtIGMoIlBNZWNvIiwgIklEIiwgImR3X2ciLCAidGltZXBvaW50X2NtdHYiLCAgInRpbWVfZCIsICJtZ0NPMl9qYXIiKQppbnZpc2libGUobGFwcGx5KGxpc3Qoc3JhLjE5YS5jbzIudHMsCiAgICAgICAgICAgICAgICAgICAgICBzcmEuMTliLmNvMi50cywKICAgICAgICAgICAgICAgICAgICAgIHNyYS4wMS4xLmNvMi50cywKICAgICAgICAgICAgICAgICAgICAgIHNyYS4wMS4yLmNvMi50cyksCiAgICAgICBmdW5jdGlvbih4KSB7CiAgICAgICAgIGlmZWxzZSghaXMubmEobWF0Y2gobm1zLCBuYW1lcyh4KSkpLCAieWVzIiwgIm5vIikKICAgICAgIH0KICAgICAgICkpCgojIGNvbWJpbmUgYWxsIGRhdGEsIHJlbW92ZSB0aW1lIHBvaW50cyB3aXRob3V0IENPMiBtZWFzdXJlbWVudHMsIGFuZCBhZGQgeWVhciBhbmQgcmVwIAp0cyA8LSBiaW5kX3Jvd3Moc3JhLjE5YS5jbzIudHNbICwgbm1zXSwgCiAgICAgICAgICAgICAgICBzcmEuMTliLmNvMi50c1sgLCBubXNdLCAKICAgICAgICAgICAgICAgIHNyYS4wMS4xLmNvMi50c1sgLCBubXNdLAogICAgICAgICAgICAgICAgc3JhLjAxLjIuY28yLnRzWyAsIG5tc10pCmlmKGxlbmd0aCh3aGljaChpcy5uYSh0cyRtZ0NPMl9qYXIpKSkgPiAwKSB7CiAgdHMgPC0gdHNbLXdoaWNoKGlzLm5hKHRzJG1nQ08yX2phcikpLCBdCn0KdHMkeWVhciA8LSBzYXBwbHkoc3Ryc3BsaXQoYXMuY2hhcmFjdGVyKHRzJElEKSwgIl8iKSwgIltbIiwgMykKdHMkcmVwIDwtIHNhcHBseShzdHJzcGxpdChhcy5jaGFyYWN0ZXIodHMkSUQpLCAiXyIpLCAiW1siLCA0KQp0cyRkZXB0aCA8LSBzYXBwbHkoc3Ryc3BsaXQoYXMuY2hhcmFjdGVyKHRzJElEKSwgIl8iKSwgIltbIiwgMikKdHMkSUQyIDwtIHBhc3RlKHRzJFBNZWNvLCB0cyRkZXB0aCwgc2VwID0gIl8iKQoKIyBhZGQgQyBjb250ZW50CnRzW3doaWNoKHRzJHllYXIgPT0gMjAwMSksICJnQ19nUyJdIDwtIHNvYy4yMDAxLnN1bTJbbWF0Y2godHNbd2hpY2godHMkeWVhciA9PSAyMDAxKSwgIklEMiJdLCBzb2MuMjAwMS5zdW0yJElEMiksICJjX3BjdF9hdmciXSAqIDEwXi0yCnRzW3doaWNoKHRzJHllYXIgPT0gMjAxOSksICJnQ19nUyJdIDwtIHNyYS4yMDE5LmNuLnN1bVttYXRjaCh0c1t3aGljaCh0cyR5ZWFyID09IDIwMTkpLCAiSUQyIl0sIHNyYS4yMDE5LmNuLnN1bSRJRDIpLCAiY19wY3RfYXZnIl0gKiAxMF4tMgoKIyBjYWxjdWxhdGUgcGVyIHVuaXQgY2FyYm9uIGZsdXhlcwp0cyRtZ0NPMl9nQyA8LSB0cyRnQ19nUyAqIHRzJGR3X2cgKiB0cyRtZ0NPMl9qYXIgKiAoMTIvNDQpCnRzJG1nQ08yX2dDX2QgPC0gdHMkbWdDTzJfZ0MgLyB0cyR0aW1lX2QKCiMgYXZlcmFnZSByZXBzCnRzLmF2ZyA8LSB0cyAlPiUKICBncm91cF9ieShQTWVjbywgeWVhciwgZGVwdGgsIHRpbWVwb2ludF9jbXR2KSAlPiUKICBzdW1tYXJpemUodGltZV9kID0gbWVhbih0aW1lX2QpLAogICAgICAgICAgICBtZ0NPMl9nQ19kX2F2ZyA9IG1lYW4obWdDTzJfZ0NfZCksCiAgICAgICAgICAgIG1nQ08yX2dDX2RfbWF4ID0gbWF4KG1nQ08yX2dDX2QpLAogICAgICAgICAgICBtZ0NPMl9nQ19kX21pbiA9IG1pbihtZ0NPMl9nQ19kKSwKICAgICAgICAgICAgbWdDTzJfZ0NfYXZnID0gbWVhbihtZ0NPMl9nQyksCiAgICAgICAgICAgIG1nQ08yX2dDX21heCA9IG1heChtZ0NPMl9nQyksCiAgICAgICAgICAgIG1nQ08yX2dDX21pbiA9IG1pbihtZ0NPMl9nQykpICU+JQogIG11dGF0ZShQTWVjb19kZXB0aF95ZWFyID0gcGFzdGUoUE1lY28sIGRlcHRoLCB5ZWFyLCBzZXAgPSAiXyIpKQoKIyBhZGQgZGVwdGggaW5kZXgKdDEgPC0gdHMuYXZnW3RzLmF2ZyR0aW1lcG9pbnRfY210diA9PSAxLCBdCnQxIDwtIGRhdGEuZnJhbWUoCiAgYmluZF9yb3dzKAogICAgbGFwcGx5KHNwbGl0KHQxLCB0MSR5ZWFyKSwgZnVuY3Rpb24oZGYpIHsKICAgICAgYmluZF9yb3dzKGxhcHBseShzcGxpdChkZiwgZGYkUE1lY28pLCBmdW5jdGlvbih4KSB7CiAgICAgICAgeCRseXJfdG9wIDwtIGFzLm51bWVyaWMoc2FwcGx5KHN0cnNwbGl0KHgkZGVwdGgsICItIiksICJbIiwgMSkpCiAgICAgICAgeCA8LSB4W29yZGVyKHgkbHlyX3RvcCksIF0KICAgICAgICB4JGRlcHRoX2luZGV4IDwtIHNlcSgxLCBucm93KHgpKQogICAgICAgIHJldHVybih4KQogICAgICB9KSkKICAgIH0pKSkKdHMuYXZnJGRlcHRoX2luZGV4IDwtIHQxW21hdGNoKHRzLmF2ZyRQTWVjb19kZXB0aF95ZWFyLCB0MSRQTWVjb19kZXB0aF95ZWFyKSwgImRlcHRoX2luZGV4Il0KCiMgY3VtdWxhdGl2ZSBmbHV4IHJhdGVzCnRzLmF2Zy5jbXR2IDwtIGJpbmRfcm93cygKICBsYXBwbHkoc3BsaXQodHMuYXZnLCB0cy5hdmckUE1lY29fZGVwdGhfeWVhciksIGZ1bmN0aW9uKHgpIHhbbnJvdyh4KSwgXSksIAogIC5pZCA9ICJQTWVjb19kZXB0aF95ZWFyIikKYGBgCgpgYGB7ciBwbG90LXJlc3AtcmF0ZXN9CmZpZy5uIDwtIDEKIyBmdW5jdGlvbiBmb3IgcGxvdHRpbmcKdHMucGxvdC5meCA8LSBmdW5jdGlvbihkZiwgeXIsIGluY3JlbWVudCwgY3VtdWxhdGl2ZSA9IFRSVUUpIHsKICAgICAgaWYgKGN1bXVsYXRpdmUpIHsKICAgICAgICBkZiAlPiUKICAgICAgICAgIGZpbHRlcih5ZWFyID09IHlyICYgZGVwdGhfaW5kZXggPT0gaW5jcmVtZW50KSAlPiUKICAgICAgICAgIG11dGF0ZShQTSA9IGlmZWxzZShncmVwbCgiQU4iLCBQTWVjbyksICJBTiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGdyZXBsKCJCUyIsIFBNZWNvKSwgIkJTIiwgIkdSIikpLAogICAgICAgICAgICAgICAgIGVjbyA9IGZhY3RvcihpZmVsc2UoZ3JlcGwoInJmIiwgUE1lY28pLCAicmYiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShncmVwbCgid2YiLCBQTWVjbyksICJ3ZiIsICJwcCIpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gYygicHAiLCAid2YiLCAicmYiKSkpICU+JQogICAgICAgICAgZ2dwbG90KC4sIGFlcyh0aW1lX2QsIG1nQ08yX2dDX2F2ZywgY29sb3IgPSBQTSwgc2hhcGUgPSBlY28pKSArCiAgICAgICAgICBnZW9tX3JpYmJvbihhZXMoeW1pbiA9IG1nQ08yX2dDX21heCwgeW1heCA9IG1nQ08yX2dDX21pbiwgZmlsbCA9IFBNLCBsaW5ldHlwZSA9IGVjbywgYWxwaGEgPSAwLjIpLCBzaG93LmxlZ2VuZCA9IEZBTFNFKSArCiAgICAgICAgICBnZW9tX3BvaW50KGFlcyh0aW1lX2QsIG1nQ08yX2dDX21heCwgZmlsbCA9IFBNLCBzaGFwZSA9IGVjbyksIGNvbG9yID0gImJsYWNrIiwgc2l6ZSA9IDMsIHN0cm9rZSA9IDEpICsKICAgICAgICAgIGdlb21fcG9pbnQoYWVzKHRpbWVfZCwgbWdDTzJfZ0NfbWluLCBmaWxsID0gUE0sIHNoYXBlID0gZWNvKSwgY29sb3IgPSAiYmxhY2siLCBzaXplID0gMywgc3Ryb2tlID0gMSkgKwogICAgICAgICAgZ2VvbV9saW5lKGFlcyhjb2xvciA9IFBNLCBsaW5ldHlwZSA9IGVjbyksIHNpemUgPSAxLjIpICsKICAgICAgICAgIGZhY2V0X2dyaWQocm93cyA9IHZhcnMoZWNvKSwKICAgICAgICAgICAgICAgICAgICAgbGFiZWxsZXIgPSBsYWJlbGxlcihlY28gPSBjKCJyZiIgPSAiY29sZCIsICJ3ZiIgPSAiY29vbCIsICJwcCIgPSAid2FybSIpKSkgKwogICAgICAgICAgc2NhbGVfeF9jb250aW51b3VzKGxpbWl0cyA9IGMoMCwzMCkpICsKICAgICAgICAgIHNjYWxlX2NvbG9yX21hbnVhbChuYW1lID0gIlBhcmVudCBtYXRlcmlhbCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiQU4iID0gImFuZGVzaXRlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJCUyIgPSAiYmFzYWx0IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJHUiIgPSAiZ3Jhbml0ZSIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9IGMoIkFOIiA9ICJibHVlIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQlMiID0gInJlZCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkdSIiA9ICJkYXJrZ3JheSIpKSArCiAgICAgICAgICBzY2FsZV9zaGFwZV9tYW51YWwobmFtZSA9ICJDbGltYXRlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCJyZiIgPSAiY29sZCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAid2YiID0gImNvb2wiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInBwIiA9ICJ3YXJtIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWVzID0gYygicHAiID0gMjEsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInJmIiA9IDIyLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJ3ZiIgPSAyNCkpICsKICAgICAgICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9YygiQU4iID0gImJsdWUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJCUyIgPSAicmVkIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiR1IiID0gImRhcmtncmF5IikpICsKICAgICAgICAgIHNjYWxlX2xpbmV0eXBlX21hbnVhbChuYW1lID0gIkNsaW1hdGUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9IGMoInJmIiA9ICJkb3R0ZWQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIndmIiA9ICJkYXNoZWQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInBwIiA9ICJzb2xpZCIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoInJmIiA9ICJjb2xkIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJ3ZiIgPSAiY29vbCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHAiID0gIndhcm0iKSkgKwogICAgICAgICAgeWxhYihleHByZXNzaW9uKCdDdW11bGF0aXZlIGZsdXggKG1nQ08nWzJdKictQyBnQydeLTEqJyknKSkgKwogICAgICAgICAgeGxhYigiVGltZSAoZGF5cykiKSArCiAgICAgICAgICBndWlkZXMoY29sb3IgPSBndWlkZV9sZWdlbmQob3JkZXIgPSAxKSwKICAgICAgICAgICAgICAgICBzaGFwZSA9IGd1aWRlX2xlZ2VuZChvcmRlciA9IDMpKSArCiAgICAgICAgICBnZ3RpdGxlKHBhc3RlKCJDdW11bGF0aXZlIGZsdXgsICIsIHlyLCAiZGVwdGggIiwgaW5jcmVtZW50KSkgKwogICAgICAgICAgdGhlbWVfYncoKSArCiAgICAgICAgICB0aGVtZShwYW5lbC5ncmlkID0gZWxlbWVudF9ibGFuaygpKQogICAgfSBlbHNlIHsKICAgICAgIGRmICU+JQogICAgICAgIGZpbHRlcih5ZWFyID09IHlyICYgZGVwdGhfaW5kZXggPT0gaW5jcmVtZW50KSAlPiUKICAgICAgICBtdXRhdGUoUE0gPSBpZmVsc2UoZ3JlcGwoIkFOIiwgUE1lY28pLCAiQU4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZ3JlcGwoIkJTIiwgUE1lY28pLCAiQlMiLCAiR1IiKSksCiAgICAgICAgICAgICAgZWNvID0gZmFjdG9yKGlmZWxzZShncmVwbCgicmYiLCBQTWVjbyksICJyZiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZ3JlcGwoIndmIiwgUE1lY28pLCAid2YiLCAicHAiKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoInBwIiwgIndmIiwgInJmIikpKSAlPiUKICAgICAgICBnZ3Bsb3QoLiwgYWVzKHRpbWVfZCwgbWdDTzJfZ0NfZF9hdmcsIGNvbG9yID0gUE0sIHNoYXBlID0gZWNvKSkgKwogICAgICAgIGdlb21fcmliYm9uKGFlcyh5bWluID0gbWdDTzJfZ0NfZF9tYXgsIHltYXggPSBtZ0NPMl9nQ19kX21pbiwgZmlsbCA9IFBNLCBsaW5ldHlwZSA9IGVjbywgYWxwaGEgPSAwLjIpLCBzaG93LmxlZ2VuZCA9IEZBTFNFKSArCiAgICAgICAgICBnZW9tX3BvaW50KGFlcyh0aW1lX2QsIG1nQ08yX2dDX2RfbWF4LCBmaWxsID0gUE0sIHNoYXBlID0gZWNvKSwgY29sb3IgPSAiYmxhY2siLCBzaXplID0gMywgc3Ryb2tlID0gMSkgKwogICAgICAgICAgZ2VvbV9wb2ludChhZXModGltZV9kLCBtZ0NPMl9nQ19kX21pbiwgZmlsbCA9IFBNLCBzaGFwZSA9IGVjbyksIGNvbG9yID0gImJsYWNrIiwgc2l6ZSA9IDMsIHN0cm9rZSA9IDEpICsKICAgICAgICBnZW9tX2xpbmUoYWVzKGNvbG9yID0gUE0sIGxpbmV0eXBlID0gZWNvKSwgc2l6ZSA9IDEuMikgKwogICAgICAgIGZhY2V0X2dyaWQocm93cyA9IHZhcnMoZWNvKSwKICAgICAgICAgICAgICAgICAgIGxhYmVsbGVyID0gbGFiZWxsZXIoZWNvID0gYygicmYiID0gImNvbGQiLCAid2YiID0gImNvb2wiLCAicHAiID0gIndhcm0iKSkpICsKICAgICAgICBzY2FsZV94X2NvbnRpbnVvdXMobGltaXRzID0gYygwLDMwKSkgKwogICAgICAgIHNjYWxlX2NvbG9yX21hbnVhbChuYW1lID0gIlBhcmVudCBtYXRlcmlhbCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIkFOIiA9ICJhbmRlc2l0ZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkJTIiA9ICJiYXNhbHQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJHUiIgPSAiZ3Jhbml0ZSIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSBjKCJBTiIgPSAiYmx1ZSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJCUyIgPSAicmVkIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkdSIiA9ICJkYXJrZ3JheSIpKSArCiAgICAgICAgc2NhbGVfc2hhcGVfbWFudWFsKG5hbWUgPSAiQ2xpbWF0ZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoInJmIiA9ICJjb2xkIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAid2YiID0gImNvb2wiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwcCIgPSAid2FybSIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSBjKCJwcCIgPSAyMSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInJmIiA9IDIyLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAid2YiID0gMjQpKSArCiAgICAgICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID1jKCJBTiIgPSAiYmx1ZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJCUyIgPSAicmVkIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkdSIiA9ICJkYXJrZ3JheSIpKSArCiAgICAgICAgc2NhbGVfbGluZXR5cGVfbWFudWFsKG5hbWUgPSAiQ2xpbWF0ZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9IGMoInJmIiA9ICJkb3R0ZWQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJ3ZiIgPSAiZGFzaGVkIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicHAiID0gInNvbGlkIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoInJmIiA9ICJjb2xkIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAid2YiID0gImNvb2wiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwcCIgPSAid2FybSIpKSArCiAgICAgICAgeWxhYihleHByZXNzaW9uKCdSZXNwaXJhdGlvbiBSYXRlIChtZ0NPJ1syXSonLUMgZ0MnXi0xKidkJ14tMSonKScpKSArCiAgICAgICAgeGxhYigiVGltZSAoZGF5cykiKSArCiAgICAgICAgZ3VpZGVzKGNvbG9yID0gZ3VpZGVfbGVnZW5kKG9yZGVyID0gMSksCiAgICAgICAgICAgICAgIHNoYXBlID0gZ3VpZGVfbGVnZW5kKG9yZGVyID0gMykpICsKICAgICAgICBnZ3RpdGxlKHBhc3RlKCJGbHV4IHJhdGUiLCB5ciwgImRlcHRoICIsIGluY3JlbWVudCkpICsKICAgICAgICB0aGVtZV9idygpICsKICAgICAgICB0aGVtZShwYW5lbC5ncmlkID0gZWxlbWVudF9ibGFuaygpKQogICAgfQp9CgojIyBjdW11bGF0aXZlIGZsdXgKIyAyMDE5CnRzLnBsb3QuZngodHMuYXZnLCB5ciA9ICIyMDE5IiwgaW5jcmVtZW50ID0gIjEiKQp0cy5wbG90LmZ4KHRzLmF2ZywgeXIgPSAiMjAxOSIsIGluY3JlbWVudCA9ICIyIikKdHMucGxvdC5meCh0cy5hdmcsIHlyID0gIjIwMTkiLCBpbmNyZW1lbnQgPSAiMyIpCiMgMjAwMQp0cy5wbG90LmZ4KHRzLmF2ZywgeXIgPSAiMjAwMSIsIGluY3JlbWVudCA9ICIxIikKdHMucGxvdC5meCh0cy5hdmcsIHlyID0gIjIwMDEiLCBpbmNyZW1lbnQgPSAiMiIpCnRzLnBsb3QuZngodHMuYXZnLCB5ciA9ICIyMDAxIiwgaW5jcmVtZW50ID0gIjMiKQoKIyMgZmx1eCByYXRlcwojIDIwMTkKdHMucGxvdC5meCh0cy5hdmcsIHlyID0gIjIwMTkiLCBpbmNyZW1lbnQgPSAiMSIsIGN1bXVsYXRpdmUgPSBGQUxTRSkKdHMucGxvdC5meCh0cy5hdmcsIHlyID0gIjIwMTkiLCBpbmNyZW1lbnQgPSAiMiIsIGN1bXVsYXRpdmUgPSBGQUxTRSkKdHMucGxvdC5meCh0cy5hdmcsIHlyID0gIjIwMTkiLCBpbmNyZW1lbnQgPSAiMyIsIGN1bXVsYXRpdmUgPSBGQUxTRSkKIyAyMDAxCnRzLnBsb3QuZngodHMuYXZnLCB5ciA9ICIyMDAxIiwgaW5jcmVtZW50ID0gIjEiLCBjdW11bGF0aXZlID0gRkFMU0UpCnRzLnBsb3QuZngodHMuYXZnLCB5ciA9ICIyMDAxIiwgaW5jcmVtZW50ID0gIjIiLCBjdW11bGF0aXZlID0gRkFMU0UpCnRzLnBsb3QuZngodHMuYXZnLCB5ciA9ICIyMDAxIiwgaW5jcmVtZW50ID0gIjMiLCBjdW11bGF0aXZlID0gRkFMU0UpCmBgYAo+KipGaWcuIGByIHtmaWcubn1gLiBSZXNwaXJhdGlvbiBkYXRhIGZyb20gaW5jdWJhdGlvbnMgb2YgMjAxOSBhbmQgMjAwMSBidWxrIHNvaWxzLiAqKgoKPipDYXB0aW9uOiogUG9pbnRzIHNob3cgbWVhc3VyZWQgQ09+Mn4gcHJvZHVjdGlvbiBvZiBsYWJvcmF0b3J5IGR1cGxpY2F0ZXMgYXMgY3VtdWxhdGl2ZSBmbHV4ZXMgb3IgZGFpbHkgZmx1eCByYXRlcyBieSBkZXB0aCwgbGluZXMgc2hvdyB0aGUgbWVhbnMsIGFuZCB0aGUgcmliYm9uIHJlcHJlc2VudHMgdGhlIHJhbmdlLiAKCmBgYHtyIHBsb3QtaW5jLWJsay0yMDE5fQojIHBsb3QgMjAxOQpmaWcubiA8LSBmaWcubiArIDEKIyBwIDwtCnNyYS4xOS5pbmMuYmxrICU+JQogIG11dGF0ZShFQ090eXBlID0gcGFzdGUwKGVjbywgIiAoIiwgVHlwZSwgIikiKSkgJT4lCiAgYXJyYW5nZShseXJfYm90KSAlPiUKICBnZ3Bsb3QoLiwgYWVzKGQxNGNfbWVhbiwgbHlyX2JvdCwgY29sb3IgPSBwbSwgc2hhcGUgPSBFQ090eXBlLCBsaW5ldHlwZSA9IFR5cGUpKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gYXRtLmQxNC4yMDE5KSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCkgKwogIGdlb21fcG9pbnQoc2l6ZSA9IDMpICsKICBnZW9tX2Vycm9yYmFyaCgKICAgIGFlcyh4bWluID0gZDE0Y19sLCAKICAgICAgICB4bWF4ID0gZDE0Y191LAogICAgICAgIGNvbG9yID0gcG0pLCAKICAgIGhlaWdodCA9IDEuNSkgKwogIGdlb21fcGF0aCgpICsKICBzY2FsZV95X3JldmVyc2UoKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKG5hbWUgPSAiUGFyZW50IG1hdGVyaWFsIiwKICAgICAgICAgICAgICAgICAgICAgdmFsdWVzID0gYygiYW5kZXNpdGUiID0gImJsdWUiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiYmFzYWx0IiA9ICJyZWQiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiZ3Jhbml0ZSIgPSAiZGFya2dyYXkiKSkgKwogIHNjYWxlX3NoYXBlX21hbnVhbChuYW1lID0gIkVjb3N5c3RlbSAodHlwZSkiLAogICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSBjKCJ3YXJtIChidWxrKSIgPSAxNSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImNvb2wgKGJ1bGspIiA9IDE2LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiY29sZCAoYnVsaykiID0gMTcsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIndhcm0gKGluYykiID0gMCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImNvb2wgKGluYykiID0gMSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImNvbGQgKGluYykiID0gMikpICsKICB4bGFiKGV4cHJlc3Npb24oRGVsdGEqJydeMTQqJ0MgKOKAsCknKSkgKwogIHlsYWIoIkRlcHRoIChjbSkiKSArCiAgZmFjZXRfZ3JpZChyb3dzID0gdmFycyhlY28pLCBjb2xzID0gdmFycyhwbSkpICsKICB0aGVtZV9idygpICsKICB0aGVtZShwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpKQojIGdnc2F2ZSgic3JhLmJ1bGtJbmMuMTkucGRmIiwgcCwgZGV2aWNlID0gY2Fpcm9fcGRmLCB3aWR0aCA9IDkuNSwgaGVpZ2h0ID0gNSwgdW5pdHMgPSAiaW4iKQpgYGAKPioqRmlnLiBgciB7ZmlnLm59YC4gJFxEZWx0YSReMTReQyBvZiAyMDE5IGJ1bGsgc29pbCBpbmN1YmF0aW9ucyBhbmQgY29ycmVzcG9uZGluZyBidWxrIHNvaWwqKgoKPipDYXB0aW9uOiogJFxEZWx0YSReMTReQyBvZiBidWxrIHNvaWwgYW5kIHJlc3BpcmVkIENPfjJ+IGJ5IGRlcHRoIGZvciBlYWNoIHNpdGUgaW4gMjAxOS4gRXJyb3IgYmFycyBzaG93IG9uZSBzdGFuZGFyZCBkZXZpYXRpb24gZm9yIGJ1bGsgc29pbCwgcG9pbnRzIHNob3cgbWVhbiBvZiB0aHJlZSByZXBsaWNhdGUgcHJvZmlsZXMgZm9yIGJ1bGsgc29pbHMgYW5kIHNpbmdsZSBvYnNlcnZhdGlvbnMgZm9yIHJlc3BpcmVkIENPfjJ+LiAKCmBgYHtyIHBsb3QtaW5jLWJsay0yMDAxfQojIHBsb3QgMjAwMQpmaWcubiA8LSBmaWcubiArIDEKc3JhLjAxLmluYy5ibGsgJT4lCiAgbXV0YXRlKEVDT3R5cGUgPSBwYXN0ZTAoZWNvLCAiICgiLCBUeXBlLCAiKSIpKSAlPiUKICBnZ3Bsb3QoLiwgYWVzKGQxNGNfbWVhbiwgbHlyX2JvdCwgY29sb3IgPSBwbSwgc2hhcGUgPSBFQ090eXBlLCBsaW5ldHlwZSA9IFR5cGUpKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gYXRtLmQxNC4yMDAxKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCkgKwogIGdlb21fcG9pbnQoc2l6ZSA9IDMpICsKICBnZW9tX2Vycm9yYmFyaCgKICAgIGFlcyh4bWluID0gZDE0Y19sLCAKICAgICAgICB4bWF4ID0gZDE0Y191LAogICAgICAgIGNvbG9yID0gcG0pLCAKICAgIGhlaWdodCA9IDEuNSkgKwogIGdlb21fcGF0aCgpICsKICBzY2FsZV95X3JldmVyc2UoKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKG5hbWUgPSAiUGFyZW50IG1hdGVyaWFsIiwKICAgICAgICAgICAgICAgICAgICAgdmFsdWVzID0gYygiYW5kZXNpdGUiID0gImJsdWUiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiYmFzYWx0IiA9ICJyZWQiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiZ3Jhbml0ZSIgPSAiZGFya2dyYXkiKSkgKwogIHNjYWxlX3NoYXBlX21hbnVhbChuYW1lID0gIkVjb3N5c3RlbSAodHlwZSkiLAogICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSBjKCJ3YXJtIChidWxrKSIgPSAxNSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImNvb2wgKGJ1bGspIiA9IDE2LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiY29sZCAoYnVsaykiID0gMTcsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIndhcm0gKGluYykiID0gMCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImNvb2wgKGluYykiID0gMSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImNvbGQgKGluYykiID0gMikpICsKICBzY2FsZV94X2NvbnRpbnVvdXMobGltaXRzID0gYygtMTAwLCAyMDApKSArCiAgeGxhYihleHByZXNzaW9uKERlbHRhKicnXjE0KidDICjigLApJykpICsKICB5bGFiKCJEZXB0aCAoY20pIikgKwogIGZhY2V0X2dyaWQocm93cyA9IHZhcnMoZWNvKSwgY29scyA9IHZhcnMocG0pKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUocGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSkKYGBgCj4qKkZpZy4gYHIge2ZpZy5ufWAuICRcRGVsdGEkXjE0XkMgb2YgMjAwMSBidWxrIHNvaWwgaW5jdWJhdGlvbnMgYW5kIGNvcnJlc3BvbmRpbmcgYnVsayBzb2lsKioKCj4qQ2FwdGlvbjoqICRcRGVsdGEkXjE0XkMgb2YgYnVsayBzb2lsIGFuZCByZXNwaXJlZCBDT34yfiBieSBkZXB0aCBmb3IgZWFjaCBzaXRlIGluIDIwMDEuIFBvaW50cyBzaG93IG1lYW4gb2YgdGhyZWUgcmVwbGljYXRlIHByb2ZpbGVzIGZvciBidWxrIHNvaWxzIGFuZCBtZWFuIG9mIGxhYm9yYXRvcnkgZHVwbGljYXRlcyBmb3IgcmVzcGlyZWQgQ09+Mn4uIFRoZSBpbmN1YmF0ZWQgc29pbCBzYW1wbGVzIGFyZSBhIGNvbXBvc2l0ZSBtYWRlIGJ5IGhvbW9nZW5pemluZyBzdWJzYW1wbGVzIGZyb20gZWFjaCBvZiB0aGUgdGhyZWUgcmVwbGljYXRlIHByb2ZpbGUgc2FtcGxlcyBieSBkZXB0aC4gRXJyb3IgYmFycyBzaG93IG9uZSBzdGFuZGFyZCBkZXZpYXRpb24gZm9yIGJ1bGsgc29pbCBhbmQgdGhlIG1lYXN1cmVkIHZhbHVlcyBmcm9tIGxhYm9yYXRvcnkgZHVwbGljYXRlcyBvZiB0aGUgaW5jdWJhdGVkIGNvbXBvc2l0ZSBzYW1wbGVzLgoKYGBge3IgcHJlcC1pbmMtYnktYnVsay0xNGMtcGxvdH0KIyBmaXJzdCBtZXJnZSBtZWFuIDE0QyBkYXRhIGZyb20gMjAxOSBzYW1wbGVzIHdpdGggY29tcG9zaXRlIGluY3ViYXRpb24gZGF0YQpubXMuaW5jLmJsayA8LSBjKCJwbSIsICJlY28iLCAibHlyX2JvdCIsICJZZWFyIikKc3JhLjE5LmluYy5ibGsyIDwtIGxlZnRfam9pbihzcmEuMTkuYnVsayAlPiUgbXV0YXRlKC4sIFllYXIgPSBhcy5mYWN0b3IoWWVhcikpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNyYS4yMDE5LmluYy5zdW0uZGYsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnkgPSBubXMuaW5jLmJsaywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdWZmaXggPSBjKCIuYnVsayIsICIuaW5jIikpCiMgMjAwMQpzcmEuMDEuaW5jLmJsazIgPC0gbGVmdF9qb2luKHNyYS4wMS5zdW0gJT4lIG11dGF0ZSguLCBZZWFyID0gYXMuZmFjdG9yKFllYXIpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzcmEuMDEuaW5jLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJ5ID0gbm1zLmluYy5ibGssCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3VmZml4ID0gYygiLmJ1bGsiLCAiLmluYyIpKQpzcmEuMDEuaW5jLmJsazIkUE1lY28gPC0gcGFzdGUwKHNyYS4wMS5pbmMuYmxrMiRwbSwgc3JhLjAxLmluYy5ibGsyJGVjbykKIyBhZGQgZGVwdGggZmFjdG9yCnNyYS4wMS5pbmMuYmxrMiA8LSB1bnNwbGl0KAogIGxhcHBseShzcGxpdChzcmEuMDEuaW5jLmJsazIsIHNyYS4wMS5pbmMuYmxrMiRQTWVjbyksIGZ1bmN0aW9uKHgpIHsKICB4JGRlcHRoIDwtIHNlcSgxLCBucm93KHgpKQogIHJldHVybih4KSAKICB9KSwgCnNyYS4wMS5pbmMuYmxrMiRQTWVjbykKc3JhLjAxLmluYy5ibGsyIDwtIHNyYS4wMS5pbmMuYmxrMlt3aGljaChzcmEuMDEuaW5jLmJsazIkbHlyX2JvdCA8IDM1KSwgXQpzcmEuMDEuaW5jLmJsazIkZGVwdGggPC0gZmFjdG9yKHNyYS4wMS5pbmMuYmxrMiRkZXB0aCkKCiMgcmVncmVzcyBidWxrIHZzLiBpbmMKbWluLmluYy5ibGsuMTkgPC0gbWluKHNyYS4xOS5pbmMuYmxrMiRkMTRjX2wuaW5jLAogICAgICAgICAgICAgICAgICAgICAgc3JhLjE5LmluYy5ibGsyJGQxNGNfbC5idWxrKSAjIGV4Y2x1ZGUgaGlnaGx5IG5lZ2F0aXZlIGluY3ViYXRpb24gc2FtcGxlIGZyb20gR1J3ZgptYXguaW5jLmJsay4xOSA8LSBtYXgoc3JhLjE5LmluYy5ibGsyJGQxNGNfbC5pbmMsCiAgICAgICAgICAgICAgICAgICAgICBzcmEuMTkuaW5jLmJsazIkZDE0Y19sLmJ1bGspCgojIFdoYXQgaXMgdGhlIGlkZWFsIGdyb3VwaW5nL2V4cGVjdGVkIHJlbGF0aW9uc2hpcD8KYGBgCgpgYGB7ciBwbG90LWluYy1ieS1idWxrLTE0Y30KIyMgbG9vayBhdCBjb21iaW5hdG9yaWFsIGRhdGFzZXQKIyBzcmEuYWxsLmRmLmZ4IDwtIGZ1bmN0aW9uKGxzLCB5ZWFyKSB7CiMgICBjYmluZChiaW5kX3Jvd3MobGFwcGx5KGxzLCBmdW5jdGlvbihkZikgZGZbICwgYygiUE1lY28iLCAibHlyX2JvdCIsICJkMTRjIildKSksCiMgICAgICAgICB5ZWFyID0geWVhcikKIyB9CiMgc3JhLmFsbC5kZiA8LSBpbm5lcl9qb2luKAojICAgcmJpbmQoc3JhLmFsbC5kZi5meChzcmEuMjAwMS5scywgMjAwMSksCiMgICAgICAgICBzcmEuYWxsLmRmLmZ4KHNyYS4yMDE5LmxzLCAyMDE5KSksCiMgICByYmluZChzcmEuYWxsLmRmLmZ4KHNyYS4yMDAxLmluYy5scywgMjAwMSksCiMgICAgICAgICBzcmEuYWxsLmRmLmZ4KHNyYS4yMDE5LmluYy5scywgMjAxOSkpLAojICAgYnkgPSBjKCJQTWVjbyIsICJseXJfYm90IiwgInllYXIiKSwKIyAgIHN1ZmZpeCA9IGMoIl9idWxrIiwgIl9pbmMiKSkKIyBzcmEuYWxsLmRmIDwtIHNyYS5hbGwuZGYgJT4lCiMgICBtdXRhdGUoUE0gPSBzdWJzdHIoUE1lY28sIDEsIDIpLAojICAgICAgICAgIEVDTyA9IHN1YnN0cihQTWVjbywgMywgNCkpCiMgCiMgc3JhLmFsbC5kZiAlPiUKIyAgIGZpbHRlcihkMTRjX2luYyA+IC0xMzApICU+JQojICAgZ2dwbG90KC4sIGFlcyhkMTRjX2J1bGssIGQxNGNfaW5jLCBjb2xvciA9IFBNKSkgKwojICAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMCkgKwojICAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCkgKwojICAgZ2VvbV9hYmxpbmUoc2xvcGUgPSAxLCBpbnRlcmNlcHQgPSAwKSArCiMgICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBmb3JtdWxhID0geSB+IHgsIGFlcyhmaWxsID0gUE0pKSArCiMgICBnZW9tX3BvaW50KCkgKwojICAgc2NhbGVfY29sb3JfbWFudWFsKG5hbWUgPSAiUGFyZW50IG1hdGVyaWFsIiwKIyAgICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSBjKCJBTiIgPSAiYmx1ZSIsCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQlMiID0gInJlZCIsCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiR1IiID0gImRhcmtncmF5IiksCiMgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiQU4iID0gImFuZGVzaXRlIiwKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJCUyIgPSAiYmFzYWx0IiwKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJHUiIgPSAiZ3Jhbml0ZSIpKSArCiMgICAgIHNjYWxlX2ZpbGxfbWFudWFsKG5hbWUgPSAiUGFyZW50IG1hdGVyaWFsIiwKIyAgICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSBjKCJBTiIgPSAiYmx1ZSIsCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQlMiID0gInJlZCIsCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiR1IiID0gImRhcmtncmF5IiksCiMgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiQU4iID0gImFuZGVzaXRlIiwKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJCUyIgPSAiYmFzYWx0IiwKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJHUiIgPSAiZ3Jhbml0ZSIpKSArCiMgICBjb29yZF9maXhlZCh4bGltID0gYygtMTMwLCAyMDApLCB5bGltID0gYygtMTMwLCAyMDApKSArCiMgICB4bGFiKGV4cHJlc3Npb24oJ0J1bGsgc29pbCAnKkRlbHRhKicnXjE0KidDICjigLApJykpICsKIyAgIHlsYWIoZXhwcmVzc2lvbignSW5jdWJhdGlvbiAnKkRlbHRhKicnXjE0KidDICjigLApJykpICsKIyAgIHRoZW1lX2J3KCkgKwojICAgdGhlbWUocGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSkKIyAgIAojIHN1bW1hcnkobG0oZDE0Y19pbmMgfiBkMTRjX2J1bGsgKiBQTSwgc3JhLmFsbC5kZltzcmEuYWxsLmRmJGQxNGNfaW5jID4gLTEzMCwgXSkpCgojIGpvaW4gYWxsIGRhdGEgYXMgbWVhbnMgYW5kIHNkcwpzcmEuYWxsLnN1bS5kZiA8LSBsZWZ0X2pvaW4oCiAgYmluZF9yb3dzKHNyYS4yMDAxLnN1bS5sczIpICU+JQogICAgc2VsZWN0KFBNZWNvLCBseXJfYm90LCBkMTRjX21lYW4sIGQxNGNfc2QpICU+JQogICAgbXV0YXRlKFllYXIgPSAyMDAxKSAlPiUKICAgIGJpbmRfcm93cyguLCAKICAgICAgICAgICAgICBiaW5kX3Jvd3MobGFwcGx5KHNyYS4yMDE5LmxzLCBmdW5jdGlvbihkZikgewogICAgICAgICAgICAgICAgZGYgJT4lCiAgICAgICAgICAgICAgICAgIGZpbHRlcihseXJfYm90IDwgMzEpICU+JQogICAgICAgICAgICAgICAgICBzZWxlY3QoUE1lY28sIGx5cl9ib3QsIGQxNGMpICU+JQogICAgICAgICAgICAgICAgICBncm91cF9ieShQTWVjbywgbHlyX2JvdCkgJT4lCiAgICAgICAgICAgICAgICAgIHN1bW1hcml6ZShhY3Jvc3MoZDE0YywgbGlzdChtZWFuID0gbWVhbiwgc2QgPSBzZCkpKSAlPiUKICAgICAgICAgICAgICAgICAgbXV0YXRlKFllYXIgPSAyMDE5KQogICAgICAgICAgICAgICAgfSkpCiAgICAgICAgICAgICksCiAgYmluZF9yb3dzKGxhcHBseShzcmEuMjAwMS5pbmMubHMsIGZ1bmN0aW9uKGRmKSB7CiAgICAgICAgICAgICAgZGYgJT4lCiAgICAgICAgICAgICAgICBzZWxlY3QoUE1lY28sIGx5cl9ib3QsIGQxNGMpICU+JQogICAgICAgICAgICAgICAgZ3JvdXBfYnkoUE1lY28sIGx5cl9ib3QpICU+JQogICAgICAgICAgICAgICAgc3VtbWFyaXplKGFjcm9zcyhkMTRjLCBsaXN0KG1lYW4gPSBtZWFuLCBzZCA9IHNkKSkpICU+JQogICAgICAgICAgICAgICAgbXV0YXRlKFllYXIgPSAyMDAxKSAKICAgICAgICAgICAgICB9KSkgJT4lCiAgYmluZF9yb3dzKC4sIAogICAgICAgICAgICBiaW5kX3Jvd3MobGFwcGx5KHNyYS4yMDE5LmluYy5scywgZnVuY3Rpb24oZGYpIHsKICAgICAgICAgICAgICBkZiAlPiUKICAgICAgICAgICAgICAgIHNlbGVjdChQTWVjbywgbHlyX2JvdCwgZDE0YykgJT4lCiAgICAgICAgICAgICAgICBncm91cF9ieShQTWVjbywgbHlyX2JvdCkgJT4lCiAgICAgICAgICAgICAgICBzdW1tYXJpemUoYWNyb3NzKGQxNGMsIGxpc3QobWVhbiA9IG1lYW4sIHNkID0gc2QpKSkgJT4lCiAgICAgICAgICAgICAgICBtdXRhdGUoWWVhciA9IDIwMTkpCiAgICAgICAgICAgICAgfSkpCiAgICAgICAgICAgICksIAogIGJ5ID0gYygiUE1lY28iLCAibHlyX2JvdCIsICJZZWFyIiksCiAgc3VmZml4ID0gYygiLmJ1bGsiLCAiLmluYyIpKSAlPiUKICBtdXRhdGUoUE0gPSBzdWJzdHJpbmcoUE1lY28sIDEsIDIpLAogICAgICAgICBlY28gPSBzdWJzdHJpbmcoUE1lY28sIDMsIDQpKQoKIyBUcmVuZCBmb3IgbWVhbnMKIyBOQiBZZWFyIG9ubHksIGRlcHRoIG9ubHkgbW9kZWxzIGRvIG5vdCBzaG93IHNpZ25pZmljYW50IGludGVyYWN0aW9ucwojIFBNIG9ubHkgbW9kZWwKZW10cmVuZHMobG0oZDE0Y19tZWFuLmluYyB+IGQxNGNfbWVhbi5idWxrICogUE0sIHNyYS5hbGwuc3VtLmRmW3NyYS5hbGwuc3VtLmRmJGQxNGNfbWVhbi5pbmMgPiAtMjAwLCBdKSwgcGFpcndpc2UgfiBQTSwgdmFyID0gImQxNGNfbWVhbi5idWxrIikKIyBFQ08gb25seSBtb2RlbAplbXRyZW5kcyhsbShkMTRjX21lYW4uaW5jIH4gZDE0Y19tZWFuLmJ1bGsgKiBlY28sIHNyYS5hbGwuc3VtLmRmW3NyYS5hbGwuc3VtLmRmJGQxNGNfbWVhbi5pbmMgPiAtMjAwLCBdKSwgcGFpcndpc2UgfiBlY28sIHZhciA9ICJkMTRjX21lYW4uYnVsayIpCgoKIyBsYXBwbHkoc3BsaXQoc3JhLmFsbC5zdW0uZGYsIHNyYS5hbGwuc3VtLmRmJGVjbyksIGZ1bmN0aW9uKGRmKSB7CiMgICBzdW1tYXJ5KGxtKGQxNGNfbWVhbi5pbmMgfiBkMTRjX21lYW4uYnVsayAqIFBNLCBkZikpCiMgfSkKCiMgIyBEZW1pbmcgcmVncmVzc2lvbiAoYWNjb3VudHMgZm9yIGVycm9yIGluIHggYW5kIHkgdGVybXMpCiMgc3JhLmRlbSA8LSBsYXBwbHkoc3BsaXQoc3JhLmFsbC5zdW0uZGYsIHNyYS5hbGwuc3VtLmRmJFBNKSwgZnVuY3Rpb24oZGYpIHsKIyAgIGRlbWluZyhkMTRjX21lYW4uaW5jIH4gZDE0Y19tZWFuLmJ1bGssCiMgICAgICAgIGRhdGEgPSBkZiwgeHN0ZCA9IGQxNGNfc2QuaW5jLCB5c3RkID0gZDE0Y19zZC5idWxrKQojIH0pCgojIGFsbCBkZXB0aHMgYW5kIHllYXJzIHRvZ2V0aGVyLCBieSBQTQpmaWcubiA8LSBmaWcubiArIDEKc3JhLjE5LmluYy5ibGsyICAlPiUKICBiaW5kX3Jvd3MoLiwgc3JhLjAxLmluYy5ibGsyWyAsIHdoaWNoKG5hbWVzKHNyYS4xOS5pbmMuYmxrMikgJWluJSBuYW1lcyhzcmEuMDEuaW5jLmJsazIpKV0pICU+JQogIG11dGF0ZShkZXB0aCA9IGZhY3RvcihseXJfYm90KSwKICAgICAgICAgZWNvWWVhciA9IHBhc3RlMChlY28sICIgKCIsIFllYXIsICIpIikpICU+JQogIGZpbHRlcihkMTRjX21lYW4uaW5jID4gLTIwMCkgJT4lCiAgZ2dwbG90KC4sIGFlcyhkMTRjX21lYW4uYnVsaywgZDE0Y19tZWFuLmluYywgY29sb3IgPSBwbSkpICsKICAjIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IGF0bS5kMTQuMjAxOSwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDApICsKICAjIGdlb21faGxpbmUoeWludGVyY2VwdCA9IGF0bS5kMTQuMjAxOSwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDApICsKICBnZW9tX2FibGluZShzbG9wZSA9IDEsIGludGVyY2VwdCA9IDApICsKICBnZW9tX3BvaW50KGFlcyhjb2xvciA9IHBtLCBzaGFwZSA9IGVjb1llYXIpLCBzaXplID0gMykgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIGZvcm11bGEgPSB5IH4geCwgc2UgPSBGQUxTRSkgKwogIGdlb21fZXJyb3JiYXJoKAogICAgYWVzKHhtaW4gPSBkMTRjX2wuYnVsaywgCiAgICAgICAgeG1heCA9IGQxNGNfdS5idWxrLAogICAgICAgIGNvbG9yID0gcG0pLCAKICAgIGhlaWdodCA9IDEuNSkgKwogIGdlb21fZXJyb3JiYXIoCiAgICBhZXMoeW1pbiA9IGQxNGNfbC5pbmMsIAogICAgICAgIHltYXggPSBkMTRjX3UuaW5jLAogICAgICAgIGNvbG9yID0gcG0pLCAKICAgIHdpZHRoID0gMS41KSArCiAgc2NhbGVfY29sb3JfbWFudWFsKG5hbWUgPSAiUGFyZW50IG1hdGVyaWFsIiwKICAgICAgICAgICAgICAgICAgICAgdmFsdWVzID0gYygiYW5kZXNpdGUiID0gYW5kZXNpdGUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImJhc2FsdCIgPSBiYXNhbHQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImdyYW5pdGUiID0gZ3Jhbml0ZSkpICsKICBzY2FsZV9zaGFwZV9tYW51YWwobmFtZSA9ICJFY29zeXN0ZW0gKHllYXIpIiwKICAgICAgICAgICAgICAgICAgICAgdmFsdWVzID0gYygid2FybSAoMjAxOSkiID0gMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiY29vbCAoMjAxOSkiID0gMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiY29sZCAoMjAxOSkiID0gMSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAid2FybSAoMjAwMSkiID0gMTUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImNvb2wgKDIwMDEpIiA9IDE3LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJjb2xkICgyMDAxKSIgPSAxNikpICsKICBjb29yZF9maXhlZCh4bGltID0gYygtMTAwLCAyMDApLCB5bGltID0gYygtMTAwLCAyMDApKSArCiAgeGxhYihleHByZXNzaW9uKCdCdWxrIHNvaWwgJypEZWx0YSonJ14xNConQyAo4oCwKScpKSArCiAgeWxhYihleHByZXNzaW9uKCdJbmN1YmF0aW9uICcqRGVsdGEqJydeMTQqJ0MgKOKAsCknKSkgKwogICMgZmFjZXRfZ3JpZChyb3dzID0gdmFycyhkZXB0aCkpICsKICB0aGVtZV9idygpICsKICB0aGVtZShwYW5lbC5ncmlkID0gZWxlbWVudF9ibGFuaygpKQoKc3JhLjE5LmluYy5ibGsyICAlPiUKICBiaW5kX3Jvd3MoLiwgc3JhLjAxLmluYy5ibGsyWyAsIHdoaWNoKG5hbWVzKHNyYS4xOS5pbmMuYmxrMikgJWluJSBuYW1lcyhzcmEuMDEuaW5jLmJsazIpKV0pICU+JQogIG11dGF0ZShkZXB0aCA9IGZhY3RvcihseXJfYm90KSwKICAgICAgICAgZWNvWWVhciA9IHBhc3RlMChlY28sICIgKCIsIFllYXIsICIpIikpICU+JQogIGZpbHRlcihkMTRjX21lYW4uaW5jID4gLTIwMCkgJT4lCiAgZ2dwbG90KC4sIGFlcyhkMTRjX21lYW4uYnVsaywgZDE0Y19tZWFuLmluYywgY29sb3IgPSBlY28pKSArCiAgIyBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBhdG0uZDE0LjIwMTksIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwKSArCiAgIyBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSBhdG0uZDE0LjIwMTksIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwKSArCiAgZ2VvbV9hYmxpbmUoc2xvcGUgPSAxLCBpbnRlcmNlcHQgPSAwKSArCiAgZ2VvbV9wb2ludChhZXMoY29sb3IgPSBlY28sIHNoYXBlID0gZWNvWWVhciksIHNpemUgPSAzKSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgZm9ybXVsYSA9IHkgfiB4LCBzZSA9IEZBTFNFKSArCiAgZ2VvbV9lcnJvcmJhcmgoCiAgICBhZXMoeG1pbiA9IGQxNGNfbC5idWxrLCAKICAgICAgICB4bWF4ID0gZDE0Y191LmJ1bGssCiAgICAgICAgY29sb3IgPSBlY28pLCAKICAgIGhlaWdodCA9IDEuNSkgKwogIGdlb21fZXJyb3JiYXIoCiAgICBhZXMoeW1pbiA9IGQxNGNfbC5pbmMsIAogICAgICAgIHltYXggPSBkMTRjX3UuaW5jLAogICAgICAgIGNvbG9yID0gZWNvKSwgCiAgICB3aWR0aCA9IDEuNSkgKwogIHNjYWxlX2NvbG9yX21hbnVhbChuYW1lID0gIkNsaW1hdGUiLAogICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSBjKCJ3YXJtIiA9IHdhcm0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImNvb2wiID0gY29vbCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiY29sZCIgPSBjb2xkKSkgKwogIHNjYWxlX3NoYXBlX21hbnVhbChuYW1lID0gIkVjb3N5c3RlbSAoeWVhcikiLAogICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSBjKCJ3YXJtICgyMDE5KSIgPSAwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJjb29sICgyMDE5KSIgPSAxLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJjb2xkICgyMDE5KSIgPSAyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJ3YXJtICgyMDAxKSIgPSAxNSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiY29vbCAoMjAwMSkiID0gMTYsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImNvbGQgKDIwMDEpIiA9IDE3KSkgKwogIGNvb3JkX2ZpeGVkKHhsaW0gPSBjKC0xMDAsIDIwMCksIHlsaW0gPSBjKC0xMDAsIDIwMCkpICsKICB4bGFiKGV4cHJlc3Npb24oJ0J1bGsgc29pbCAnKkRlbHRhKicnXjE0KidDICjigLApJykpICsKICB5bGFiKGV4cHJlc3Npb24oJ0luY3ViYXRpb24gJypEZWx0YSonJ14xNConQyAo4oCwKScpKSArCiAgIyBmYWNldF9ncmlkKHJvd3MgPSB2YXJzKGRlcHRoKSkgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCkpCgojICMgMjAwMQojIHNyYS4wMS5pbmMuYmxrMiAlPiUKIyAgIGZpbHRlcihkMTRjX21lYW4uYnVsayA+IC0xMDAgJiBkMTRjX21lYW4uaW5jID4gLTEwMCkgJT4lCiMgICBnZ3Bsb3QoLiwgYWVzKGQxNGNfbWVhbi5idWxrLCBkMTRjX21lYW4uaW5jLCBjb2xvciA9IHBtLCBzaGFwZSA9IGVjbywgZ3JvdXAgPSBwbSkpICsKIyAgICMgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gYXRtLmQxNC4yMDE5LCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiMgICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwKSArCiMgICAjIGdlb21faGxpbmUoeWludGVyY2VwdCA9IGF0bS5kMTQuMjAxOSwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwojICAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCkgKwojICAgZ2VvbV9hYmxpbmUoc2xvcGUgPSAxLCBpbnRlcmNlcHQgPSAwKSArCiMgICBnZW9tX3BvaW50KHNpemUgPSAzKSArCiMgICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBmb3JtdWxhID0geSB+IHgsIHNlID0gRkFMU0UpICsKIyAgIGdlb21fZXJyb3JiYXJoKAojICAgICBhZXMoeG1pbiA9IGQxNGNfbC5idWxrLCAKIyAgICAgICAgIHhtYXggPSBkMTRjX3UuYnVsaywKIyAgICAgICAgIGNvbG9yID0gcG0pLCAKIyAgICAgaGVpZ2h0ID0gMS41KSArCiMgICBnZW9tX2Vycm9yYmFyKAojICAgICBhZXMoeW1pbiA9IGQxNGNfbC5pbmMsIAojICAgICAgICAgeW1heCA9IGQxNGNfdS5pbmMsCiMgICAgICAgICBjb2xvciA9IHBtKSwgCiMgICAgIHdpZHRoID0gMS41KSArCiMgICBzY2FsZV9jb2xvcl9tYW51YWwobmFtZSA9ICJQYXJlbnQgbWF0ZXJpYWwiLAojICAgICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9IGMoImFuZGVzaXRlIiA9ICJibHVlIiwKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJiYXNhbHQiID0gInJlZCIsCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiZ3Jhbml0ZSIgPSAiZGFya2dyYXkiKSkgKwojICAgc2NhbGVfc2hhcGVfbWFudWFsKG5hbWUgPSAiRWNvc3lzdGVtIiwKIyAgICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSBjKCJ3YXJtIiA9IDE1LAojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImNvb2wiID0gMTYsCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiY29sZCIgPSAxNykpICsKIyAgIGNvb3JkX2ZpeGVkKHhsaW0gPSBjKC0xMDAsIDIwMCksIHlsaW0gPSBjKC0xMDAsIDIwMCkpICsKIyAgIHhsYWIoZXhwcmVzc2lvbignQnVsayBzb2lsICcqRGVsdGEqJydeMTQqJ0MgKOKAsCknKSkgKwojICAgeWxhYihleHByZXNzaW9uKCdJbmN1YmF0aW9uICcqRGVsdGEqJydeMTQqJ0MgKOKAsCknKSkgKwojICAgZmFjZXRfZ3JpZChyb3dzID0gdmFycyhkZXB0aCkpICsKIyAgIHRoZW1lX2J3KCkgKwojICAgdGhlbWUocGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSkKIyAKIyAjIDIwMTkKIyBmaWcubiA8LSBmaWcubiArIDEKIyBzcmEuMTkuaW5jLmJsazIgJT4lCiMgICBtdXRhdGUoZGVwdGggPSBmYWN0b3IobHlyX2JvdCkpICU+JQojICAgZ2dwbG90KC4sIGFlcyhkMTRjX21lYW4uYnVsaywgZDE0Y19tZWFuLmluYywgY29sb3IgPSBwbSwgc2hhcGUgPSBlY28sIGdyb3VwID0gcG0pKSArCiMgICAjIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IGF0bS5kMTQuMjAxOSwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwojICAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMCkgKwojICAgIyBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSBhdG0uZDE0LjIwMTksIGxpbmV0eXBlID0gImRhc2hlZCIpICsKIyAgIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDApICsKIyAgIGdlb21fYWJsaW5lKHNsb3BlID0gMSwgaW50ZXJjZXB0ID0gMCkgKwojICAgZ2VvbV9wb2ludChzaXplID0gMykgKwojICAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgZm9ybXVsYSA9IHkgfiB4LCBzZSA9IEZBTFNFKSArCiMgICBnZW9tX2Vycm9yYmFyaCgKIyAgICAgYWVzKHhtaW4gPSBkMTRjX2wuYnVsaywgCiMgICAgICAgICB4bWF4ID0gZDE0Y191LmJ1bGssCiMgICAgICAgICBjb2xvciA9IHBtKSwgCiMgICAgIGhlaWdodCA9IDEuNSkgKwojICAgZ2VvbV9lcnJvcmJhcigKIyAgICAgYWVzKHltaW4gPSBkMTRjX2wuaW5jLCAKIyAgICAgICAgIHltYXggPSBkMTRjX3UuaW5jLAojICAgICAgICAgY29sb3IgPSBwbSksIAojICAgICB3aWR0aCA9IDEuNSkgKwojICAgc2NhbGVfY29sb3JfbWFudWFsKG5hbWUgPSAiUGFyZW50IG1hdGVyaWFsIiwKIyAgICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSBjKCJhbmRlc2l0ZSIgPSAiYmx1ZSIsCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiYmFzYWx0IiA9ICJyZWQiLAojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImdyYW5pdGUiID0gImRhcmtncmF5IikpICsKIyAgIHNjYWxlX3NoYXBlX21hbnVhbChuYW1lID0gIkVjb3N5c3RlbSIsCiMgICAgICAgICAgICAgICAgICAgICAgdmFsdWVzID0gYygid2FybSIgPSAwLAojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImNvb2wiID0gMSwKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJjb2xkIiA9IDIpKSArCiMgICBjb29yZF9maXhlZCh4bGltID0gYygtMTAwLCAyMDApLCB5bGltID0gYygtMTAwLCAyMDApKSArCiMgICB4bGFiKGV4cHJlc3Npb24oJ0J1bGsgc29pbCAnKkRlbHRhKicnXjE0KidDICjigLApJykpICsKIyAgIHlsYWIoZXhwcmVzc2lvbignSW5jdWJhdGlvbiAnKkRlbHRhKicnXjE0KidDICjigLApJykpICsKIyAgIGZhY2V0X2dyaWQocm93cyA9IHZhcnMoZGVwdGgpKSArCiMgICB0aGVtZV9idygpICsKIyAgIHRoZW1lKHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCkpCmBgYAo+KipGaWcuIGByIHtmaWcubn1gLiBSZWdyZXNzaW9uIG9mIDIwMTkgYnVsayBzb2lsIGluY3ViYXRpb25zIGFuZCBjb3JyZXNwb25kaW5nIGJ1bGsgc29pbCAkXERlbHRhJF4xNF5DKioKCj4qQ2FwdGlvbjoqIFJlZ3Jlc3Npb25zIG9mICRcRGVsdGEkXjE0XkMgb2YgYnVsayBzb2lsIGFuZCByZXNwaXJlZCBDT34yfiBieSBkZXB0aCBmb3IgZWFjaCBzaXRlIGluIDIwMTkuIEVycm9yIGJhcnMgc2hvdyBvbmUgc3RhbmRhcmQgZGV2aWF0aW9uIGZvciBidWxrIHNvaWwsIHBvaW50cyBzaG93IG1lYW4gb2YgdGhyZWUgcmVwbGljYXRlIHByb2ZpbGVzIGZvciBidWxrIHNvaWxzIGFuZCBzaW5nbGUgb2JzZXJ2YXRpb25zIGZvciByZXNwaXJlZCBDT34yfi4KCiMjIFRpbWUgc2VyaWVzOiAkXERlbHRhJF4xNF5DIGJ5IGRlcHRoIChhcyBtZWFzdXJlZCkKYGBge3IgcGxvdC10aW1lc2VyaWVzLW1lYXMtZGVwdGhzfQojIGNvbWJpbmUgJzAxLCAnMDksICcxOSBkYXRhCnNyYS4wMS4xOS5yYXcgPC0gcmJpbmQoYmluZF9yb3dzKHNyYS4yMDAxLnN1bS5scyksCiAgICAgICAgICAgICAgICAgICAgICAgYmluZF9yb3dzKHNyYS4yMDE5LnN1bS5scykpCnNyYS4yMDA5LmRmIDwtIHNyYS4wOS5zdW1bICwgd2hpY2gobmFtZXMoc3JhLjA5LnN1bSkgJWluJSBuYW1lcyhzcmEuMDEuMTkucmF3KSldCnNyYS4yMDA5LmRmIDwtIGNiaW5kKHNyYS4yMDA5LmRmLCAKICAgICAgICAgICAgICAgICAgICAgZm0gPSBOQSwKICAgICAgICAgICAgICAgICAgICAgZDE0Y19zZCA9IE5BLAogICAgICAgICAgICAgICAgICAgICBmbV9zZCA9IE5BLAogICAgICAgICAgICAgICAgICAgICBkMTRjX3UgPSBOQSwKICAgICAgICAgICAgICAgICAgICAgZDE0Y19sID0gTkEpCnNyYS4wMS4wOS4xOS5yYXcgPC0gcmJpbmQoc3JhLjAxLjE5LnJhdywgc3JhLjIwMDkuZGYpCnNyYS4wMS4wOS4xOS5yYXckWWVhciA8LSBmYWN0b3IoYyhyZXAoMjAwMSwgbnJvdyhiaW5kX3Jvd3Moc3JhLjIwMDEuc3VtLmxzKSkpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVwKDIwMTksIG5yb3coYmluZF9yb3dzKHNyYS4yMDE5LnN1bS5scykpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlcCgyMDA5LCBucm93KHNyYS4yMDA5LmRmKSkpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoIjIwMDEiLCAiMjAwOSIsICIyMDE5IikpCgojIHBsb3QKIyB3LyByaWJib25zCiMgc3JhLjAxLjA5LjE5LnJhdyAlPiUKIyAgIG11dGF0ZShQTWVjb195ZWFyID0gcGFzdGUwKFBNZWNvLCBZZWFyKSwKIyAgICAgICAgICBlY28gPSBmYWN0b3IoaWZlbHNlKEVDTyA9PSAicHAiLCAid2FybSIsCiMgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShFQ08gPT0gIndmIiwgImNvb2wiLCAiY29sZCIpKSwKIyAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gYygid2FybSIsICJjb29sIiwgImNvbGQiKSksCiMgICAgICAgICAgZDE0Y191ID0gZDE0YyArIGQxNGNfc2QsCiMgICAgICAgICAgZDE0Y19sID0gZDE0YyAtIGQxNGNfc2QsCiMgICAgICAgICAgcG0gPSBpZmVsc2UoUE0gPT0gIkFOIiwgImFuZGVzaXRlIiwKIyAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoUE0gPT0gIkJTIiwgImJhc2FsdCIsICJncmFuaXRlIikpKSAlPiUKIyAgIGdncGxvdCguLCBhZXMoZDE0YywgbHlyX2JvdCwgZ3JvdXAgPSBQTWVjb195ZWFyKSkgKwojICAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMCkgKwojICAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCkgKwojICAgZ2VvbV9yaWJib24oYWVzKHhtaW4gPSBkMTRjX2wsIHhtYXggPSBkMTRjX3UsIGZpbGwgPSBwbSwgYWxwaGEgPSBZZWFyLCBncm91cCA9IFBNZWNvX3llYXIpLAojICAgICAgICAgICAgICAgY29sb3IgPSBOQSwgc2hvdy5sZWdlbmQgPSBGQUxTRSkgKwojICAgZ2VvbV9wb2ludChhZXMoZmlsbCA9IHBtLCBjb2xvciA9IHBtLCBzaGFwZSA9IGVjbywgYWxwaGEgPSBZZWFyKSwgc2l6ZSA9IDIpICsKIyAgIGdlb21fcG9pbnQoYWVzKHNoYXBlID0gZWNvKSwgY29sb3IgPSAiYmxhY2siLCBzaXplID0gMykgKwojICAgZ2VvbV9wYXRoKGFlcyhsaW5ldHlwZSA9IFllYXIsIGNvbG9yID0gcG0pLCBzaXplID0gMC43KSArCiMgICBzY2FsZV95X3JldmVyc2UoKSArCiMgICBzY2FsZV9jb2xvcl9tYW51YWwobmFtZSA9ICJQYXJlbnQgbWF0ZXJpYWwiLAojICAgICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9IGMoImFuZGVzaXRlIiA9ICJibHVlIiwgCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiYmFzYWx0IiA9ICJyZWQiLCAKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJncmFuaXRlIiA9ICJkYXJrZ3JheSIpKSArCiMgICBzY2FsZV9maWxsX21hbnVhbChuYW1lID0gIlBhcmVudCBtYXRlcmlhbCIsCiMgICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSBjKCJhbmRlc2l0ZSIgPSAiYmx1ZSIsIAojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiYmFzYWx0IiA9ICJyZWQiLCAKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImdyYW5pdGUiID0gImRhcmtncmF5IikpICsKIyAgIHNjYWxlX3NoYXBlX21hbnVhbChuYW1lID0gIkVjb3N5c3RlbSIsCiMgICAgICAgICAgICAgICAgICAgICAgdmFsdWVzID0gYygid2FybSIgPSAyMiwgCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiY29vbCIgPSAyMSwgCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiY29sZCIgPSAyNCkpICsKIyAgIHNjYWxlX2FscGhhX21hbnVhbCh2YWx1ZXMgPSBjKCIyMDAxIiA9IC42LAojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjIwMDkiID0gMC40LAojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjIwMTkiID0gMC4yKSkgKwojICAgZmFjZXRfZ3JpZChyb3dzID0gdmFycyhlY28pLCBjb2xzID0gdmFycyhwbSkpICsKIyAgIHhsYWIoZXhwcmVzc2lvbihEZWx0YSonJ14xNConQyAo4oCwKScpKSArCiMgICB5bGFiKCJEZXB0aCAoY20pIikgKwojICAgdGhlbWVfYncoKSArCiMgICB0aGVtZShwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpKQoKIyBsaXR0ZXIKc3JhLjIwMTkuaW5jLkwuZGYgPC0gZGF0YS5mcmFtZSgKICBzcmEuMjAxOS5pbmNfTC5kZiAlPiUKICAgIGdyb3VwX2J5KFllYXIsIFBNLCBlY28sIGx5cl9ib3QsIFBNZWNvKSAlPiUKICAgIHN1bW1hcml6ZShhY3Jvc3MoLmNvbHMgPSBkMTRjLCAKICAgICAgICAgICAgICAgICAgICAgLmZucyA9IGxpc3QobWVhbiA9IG1lYW4sIG1pbiA9IG1pbiwgbWF4ID0gbWF4KSkpICU+JQogICAgcmVuYW1lKHllYXIgPSBZZWFyLCBkMTRjID0gZDE0Y19tZWFuKSAlPiUKICAgIG11dGF0ZShlY28gPSBmYWN0b3IoaWZlbHNlKGVjbyA9PSAicHAiLCAid2FybSIsCiAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZWNvID09ICJ3ZiIsICJjb29sIiwgImNvbGQiKSksCiAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSBjKCJ3YXJtIiwgImNvb2wiLCAiY29sZCIpKSwKICAgICAgICAgICBwbSA9IGlmZWxzZShQTSA9PSAiQU4iLCAiYW5kZXNpdGUiLAogICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShQTSA9PSAiQlMiLCAiYmFzYWx0IiwgImdyYW5pdGUiKSkpKQojIGZvciBwbG90dGluZyBiZWxvdwpzcmEuMjAxOS5pbmMuTC5kZjIgPC0gc3JhLjIwMTkuaW5jLkwuZGYgJT4lCiAgcmVuYW1lKGQxNGNfbCA9IGQxNGNfbWluLAogICAgICAgICBkMTRjX3UgPSBkMTRjX21heCkgJT4lCiAgbXV0YXRlKFBNZWNvX3llYXIgPSBwYXN0ZTAoUE1lY28sIHllYXIpKQoKIyB3aXRoIGVycm9yIGJhcnMsIGFsbCBkZXB0aHMKc3JhLjAxLjA5LjE5LnJhdyAlPiUKICBtdXRhdGUoUE1lY29feWVhciA9IHBhc3RlMChQTWVjbywgWWVhciksCiAgICAgICAgIGVjbyA9IGZhY3RvcihpZmVsc2UoRUNPID09ICJwcCIsICJ3YXJtIiwKICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShFQ08gPT0gIndmIiwgImNvb2wiLCAiY29sZCIpKSwKICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoIndhcm0iLCAiY29vbCIsICJjb2xkIikpLAogICAgICAgICBkMTRjX3UgPSBkMTRjICsgZDE0Y19zZCwKICAgICAgICAgZDE0Y19sID0gZDE0YyAtIGQxNGNfc2QsCiAgICAgICAgIHBtID0gaWZlbHNlKFBNID09ICJBTiIsICJhbmRlc2l0ZSIsCiAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShQTSA9PSAiQlMiLCAiYmFzYWx0IiwgImdyYW5pdGUiKSkpICU+JQogIGdncGxvdCguLCBhZXMoZDE0YywgbHlyX2JvdCwgZ3JvdXAgPSBQTWVjb195ZWFyKSkgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDApICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwKSArCiAgZ2VvbV9wb2ludChhZXMoZmlsbCA9IHBtLCBjb2xvciA9IHBtLCBzaGFwZSA9IGVjbywgYWxwaGEgPSBZZWFyKSwgc2l6ZSA9IDMuNSkgKwogIGdlb21fcG9pbnQoZGF0YSA9IHNyYS4yMDE5LmluYy5MLmRmMiwgCiAgICAgICAgICAgICBhZXMoZDE0YywgbHlyX2JvdCwgY29sb3IgPSBwbSwgc2hhcGUgPSBlY28pLCBzaGFwZSA9IDgsIHNpemUgPSAzLjUsIHNob3cubGVnZW5kID0gRkFMU0UpICsKICBnZW9tX3BhdGgoYWVzKGxpbmV0eXBlID0gWWVhciwgY29sb3IgPSBwbSksIHNpemUgPSAwLjcpICsKICBnZW9tX2Vycm9yYmFyaCgKICAgIGFlcyh4bWluID0gZDE0Y19sLAogICAgICAgIHhtYXggPSBkMTRjX3UsCiAgICAgICAgY29sb3IgPSBwbSwKICAgICAgICBhbHBoYSA9IFllYXIpLAogICAgaGVpZ2h0ID0gMS41KSArCiAgc2NhbGVfeV9yZXZlcnNlKCkgKwogIHNjYWxlX2NvbG9yX21hbnVhbChuYW1lID0gIlBhcmVudCBtYXRlcmlhbCIsCiAgICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9IGMoImFuZGVzaXRlIiA9ICJibHVlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiYmFzYWx0IiA9ICJyZWQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJncmFuaXRlIiA9ICJkYXJrZ3JheSIpKSArCiAgc2NhbGVfZmlsbF9tYW51YWwobmFtZSA9ICJQYXJlbnQgbWF0ZXJpYWwiLAogICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9IGMoImFuZGVzaXRlIiA9ICJibHVlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJiYXNhbHQiID0gInJlZCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiZ3Jhbml0ZSIgPSAiZGFya2dyYXkiKSkgKwogIHNjYWxlX3NoYXBlX21hbnVhbChuYW1lID0gIkVjb3N5c3RlbSIsCiAgICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9IGMoIndhcm0iID0gMTUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImNvb2wiID0gMTYsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImNvbGQiID0gMTcpKSArCiAgc2NhbGVfYWxwaGFfbWFudWFsKHZhbHVlcyA9IGMoIjIwMDEiID0gMSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiMjAwOSIgPSAwLjYsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjIwMTkiID0gMC4zKSkgKwogIHNjYWxlX2xpbmV0eXBlX21hbnVhbCh2YWx1ZXMgPSBjKCIyMDAxIiA9IDEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjIwMDkiID0gMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiMjAxOSIgPSAzKSkgKwogIGZhY2V0X2dyaWQocm93cyA9IHZhcnMoZWNvKSwgY29scyA9IHZhcnMocG0pKSArCiAgeGxhYihleHByZXNzaW9uKERlbHRhKicnXjE0KidDICjigLApJykpICsKICB5bGFiKCJEZXB0aCAoY20pIikgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCkpCgojIGp1c3QgdG9wc29pbCwgdy8gZXJyb3IgYmFycwpmaWcubiA8LSBmaWcubiArIDEKc3JhLjAxLjA5LjE5LnJhdyA8LSBzcmEuMDEuMDkuMTkucmF3W29yZGVyKHNyYS4wMS4wOS4xOS5yYXckbHlyX3RvcCksIF0Kc3JhLjAxLjA5LjE5LnJhdyAlPiUKICBtdXRhdGUoUE1lY29feWVhciA9IHBhc3RlMChQTWVjbywgWWVhciksCiAgICAgICAgIGVjbyA9IGZhY3RvcihpZmVsc2UoRUNPID09ICJwcCIsICJ3YXJtIiwKICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShFQ08gPT0gIndmIiwgImNvb2wiLCAiY29sZCIpKSwKICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoIndhcm0iLCAiY29vbCIsICJjb2xkIikpLAogICAgICAgICBkMTRjX3UgPSBkMTRjICsgZDE0Y19zZCwKICAgICAgICAgZDE0Y19sID0gZDE0YyAtIGQxNGNfc2QsCiAgICAgICAgIHBtID0gaWZlbHNlKFBNID09ICJBTiIsICJhbmRlc2l0ZSIsCiAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShQTSA9PSAiQlMiLCAiYmFzYWx0IiwgImdyYW5pdGUiKSkpICU+JQogIGdncGxvdCguLCBhZXMoZDE0YywgbHlyX2JvdCwgZ3JvdXAgPSBQTWVjb195ZWFyKSkgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDApICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwKSArCiAgZ2VvbV9wb2ludChhZXMoZmlsbCA9IHBtLCBjb2xvciA9IHBtLCBzaGFwZSA9IGVjbywgYWxwaGEgPSBZZWFyKSwgc2l6ZSA9IDMpICsKICBnZW9tX3BhdGgoYWVzKGxpbmV0eXBlID0gWWVhciwgY29sb3IgPSBwbSksIHNpemUgPSAwLjcpICsKICBnZW9tX2Vycm9yYmFyaCgKICAgIGFlcyh4bWluID0gZDE0Y19sLAogICAgICAgIHhtYXggPSBkMTRjX3UsCiAgICAgICAgY29sb3IgPSBwbSwKICAgICAgICBhbHBoYSA9IFllYXIpLAogICAgaGVpZ2h0ID0gMS41KSArCiAgc2NhbGVfeV9yZXZlcnNlKGxpbWl0cyA9IGMoNDEsIDApKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGxpbWl0cyA9IGMoLTE2MCwgMTkwKSkgKwogIHNjYWxlX2NvbG9yX21hbnVhbChuYW1lID0gIlBhcmVudCBtYXRlcmlhbCIsCiAgICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9IGMoImFuZGVzaXRlIiA9ICJibHVlIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImJhc2FsdCIgPSAicmVkIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImdyYW5pdGUiID0gImRhcmtncmF5IikpICsKICBzY2FsZV9maWxsX21hbnVhbChuYW1lID0gIlBhcmVudCBtYXRlcmlhbCIsCiAgICAgICAgICAgICAgICAgICAgdmFsdWVzID0gYygiYW5kZXNpdGUiID0gImJsdWUiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJiYXNhbHQiID0gInJlZCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImdyYW5pdGUiID0gImRhcmtncmF5IikpICsKICBzY2FsZV9zaGFwZV9tYW51YWwobmFtZSA9ICJFY29zeXN0ZW0iLAogICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSBjKCJ3YXJtIiA9IDE1LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiY29vbCIgPSAxNiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImNvbGQiID0gMTcpKSArCiAgc2NhbGVfYWxwaGFfbWFudWFsKHZhbHVlcyA9IGMoIjIwMDEiID0gMSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiMjAwOSIgPSAwLjYsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjIwMTkiID0gMC4zKSkgKwogIHNjYWxlX2xpbmV0eXBlX21hbnVhbCh2YWx1ZXMgPSBjKCIyMDAxIiA9ICJzb2xpZCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjIwMDkiID0gImRhc2hlZCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjIwMTkiID0gImRvdHRlZCIpKSArCiAgZmFjZXRfZ3JpZChyb3dzID0gdmFycyhlY28pLCBjb2xzID0gdmFycyhwbSkpICsKICB4bGFiKGV4cHJlc3Npb24oRGVsdGEqJydeMTQqJ0MgKOKAsCknKSkgKwogIHlsYWIoIkRlcHRoIChjbSkiKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUocGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSkKYGBgCj4qKkZpZy4gYHIge2ZpZy5ufWAuIFRpbWUgc2VyaWVzIG9mICRcRGVsdGEkXjE0XkMgYnkgZGVwdGgsIGFzIG1lYXN1cmVkKioKCj4qQ2FwdGlvbjoqIFBvaW50cyBzaG93IG1lYW4gb2YgdGhyZWUgcHJvZmlsZSByZXBsaWNhdGVzIGZvciAyMDAxLCAyMDA5LCBhbmQgMjAxOSBzYW1wbGVzLiBFcnJvciBiYXJzIHNob3cgwrEgMSBzdGFuZGFyZCBkZXZpYXRpb24gb2YgdGhlIG1lYW4gKG9ubHkgYSBzaW5nbGUgcHJvZmlsZSB3YXMgYW5hbHl6ZWQgaW4gMjAwOSkuIFN0YXJzIHNob3cgbGl0dGVyIGluY3ViYXRpb24gJFxEZWx0YSReMTReQy1DT34yfiBmb3IgMjAxOSBzYW1wbGVzIGFzIGEgcG9pbnQgb2YgcmVmZXJlbmNlLgoKIyMgU3BsaW5lIGZpdHRpbmcKClNvaWxzIGNvbGxlY3RlZCBpbiBib3RoIHRoZSAyMDAxIGFuZCAyMDA5IHNhbXBsaW5nIGNhbXBhaWducyB3ZXJlIHNhbXBsZWQgYnkgaG9yaXpvbiwgYnV0IHRoZSBkZXB0aCBpbnRlcnZhbHMgZGlmZmVyZWQgYmV0d2VlbiB0aGUgdHdvIHNhbXBsaW5nIHllYXJzLiBJbiAyMDA5LCBmdWxsIHByb2ZpbGVzIHdlcmUgZXhjYXZhdGVkIGZvciBlYWNoIHNpdGUsIGFzIG9wcG9zZWQgdG8gdGhlIHNob3J0ZXIgcHJvZmlsZXMgY29sbGVjdGVkIGluIDIwMDEgZnJvbSB0aGUgR1IgYW5kIEFOIHNpdGVzLiBSYWRpb2NhcmJvbiB3YXMgbWVhc3VyZWQgb24gYWxsIHRocmVlIHJlcGxpY2F0ZSBwcm9maWxlcyBhdCBlYWNoIHNpdGUgZm9yIHRoZSAyMDAxIHNhbXBsZXMsIGJ1dCBvbmx5IGZvciBvbmUgb2YgdGhlIHJlcGxpY2F0ZSBwcm9maWxlcyBhdCBlYWNoIHNpdGUgaW4gMjAwOSwgZS5nLiBBTnBwIHJlcDIsIGV0Yy4KCkluIG9yZGVyIHRvIGNvbXBhcmUgdGhlIHJhZGlvY2FyYm9uIHByb2ZpbGVzIGJldHdlZW4gMjAwMSwgMjAwOSwgYW5kIDIwMTkgd2UgZmlyc3QgaW50ZXJwb2xhdGVkIGJvdGggcmFkaW9jYXJib24gYW5kIGNhcmJvbiBzdG9jayBkYXRhIGF0IDEgY20gaW50ZXJ2YWxzIGZvciBlYWNoIHNpdGUgaW4gdGhlIGRhdGFzZXRzIGZyb20gZWFjaCB5ZWFyLiBUaGUgY2FyYm9uLXN0b2NrLXdlaWdodGVkIHJhZGlvY2FyYm9uIHZhbHVlcyBmb3IgYW55IGdpdmVuIHRhcmdldCBkZXB0aCBpbnRlcnZhbCBjYW4gdGhlbiBiZSBjYWxjdWxhdGVkIGFzIGEgc2ltcGxlIHN1bSBvZiB0aGUgcHJvZHVjdCBvZiB0aGUgY2FyYm9uIHdlaWdodCBvZiBlYWNoIDEgY20gaW5jcmVtZW50IChyZWxhdGl2ZSB0byB0aGUgdG90YWwgY2FyYm9uIHN0b2NrIG9mIHRoZSB0YXJnZXQgZGVwdGggaW50ZXJ2YWwpIGFuZCBpdHMgcmFkaW9jYXJib24gdmFsdWUuIEEgbW9ub3RvbmljIGN1YmljIHNwbGluZSBmaXQgd2l0aCBIeW1hbiBmaWx0ZXJpbmcgd2FzIHVzZWQgZm9yIHRoZSBjYXJib24gc3RvY2sgaW50ZXJwb2xhdGlvbiAoV2VuZHQgYW5kIEhhdXNlciAyMDEzKSwgYW5kIGEgbWFzcy1wcmVzZXJ2aW5nIHNwbGluZSB3YXMgdXNlZCB0byBmaXQgdGhlIHJhZGlvY2FyYm9uIGRhdGEgKEJpc2hvcCwgVC5GLkEuLCBNY0JyYXRuZXksIEEuQi4sIExhc2xldHQsIEcuTS4sICgxOTk5KSBNb2RlbGxpbmcgc29pbCBhdHRyaWJ1dGUgZGVwdGggZnVuY3Rpb25zIHdpdGggZXF1YWwtYXJlYSBxdWFkcmF0aWMgc21vb3RoaW5nIHNwbGluZXMuIEdlb2Rlcm1hLCA5MSgxLTIpOiAyNy00NSkuCgpgYGB7ciBjbi1jbGVhbiwgaW5jbHVkZSA9IEZBTFNFfQplbG1fcmVzdWx0c19kZiA8LSBiaW5kX3Jvd3ModW5saXN0KGVsbV9yZXN1bHRzX2xzLCByZWN1cnNpdmUgPSBGQUxTRSkpCiMgU3BsaXQgSURzClBNZWNvX3JlcF9kZXB0aCA8LSBiaW5kX3Jvd3MoCiAgbGFwcGx5KHN0cnNwbGl0KGVsbV9yZXN1bHRzX2RmJElELCAiXyIpLCBmdW5jdGlvbih4KSB7IAogICAgZGYgPC0gIGRhdGEuZnJhbWUoUE1lY28gPSB4WzJdLAogICAgICAgICAgICAgICAgICAgICAgcHJvX3JlcCA9IHhbM10sCiAgICAgICAgICAgICAgICAgICAgICBkZXB0aCA9IHhbNF0pCiAgICBkZiRQTSA8LSBzdWJzdHIoZGYkUE1lY28sIDEsIDIpCiAgICBkZiRFQ08gPC0gc3Vic3RyKGRmJFBNZWNvLCAzLCA0KQogICAgcmV0dXJuKGRmKQogIH0pCikKZWxtX3Jlc3VsdHNfZGYgPC0gY2JpbmQoZWxtX3Jlc3VsdHNfZGYsIFBNZWNvX3JlcF9kZXB0aCkKYGBgCgpgYGB7ciBzb2MtMjAwMSwgaW5jbHVkZSA9IEZBTFNFfQojIG1lcmdlIHNvYy4yMDAxLmxzIGFuZCBzcmEuMjAwMS5scyB0byBhZGQgU09DIGRhdGEKc3JhLjIwMDEubHMgPC0gbWFwcGx5KG1lcmdlLCBzcmEuMjAwMS5scywgc29jLjIwMDEubHMsIFNJTVBMSUZZID0gRkFMU0UpCgojIGNhbGN1bGF0ZSBjdW11bGF0aXZlIHN0b2NrcwpzcmEuMjAwMS5scyA8LSBsYXBwbHkoc3JhLjIwMDEubHMsIGZ1bmN0aW9uKGRmKSB7CiAgbHMgPC0gc3BsaXQoZGYsIGRmJHByb19uYW1lKQogIGxzIDwtIGxhcHBseShscywgZnVuY3Rpb24oeCkgewogICAgeCA8LSB4W29yZGVyKHgkbHlyX2JvdCksIF0gIyBtYWtlIHN1cmUgdG8gb3JkZXIgZGF0YQogICAgeCRseXJfc29jX2NtdHYgPC0gTkEKICAgIGZvcihpIGluIHNlcV9hbG9uZyh4JGx5cl9ib3QpKSB7CiAgICAgIGlmKGkgPT0gMSkgewogICAgICAgIHgkbHlyX3NvY19jbXR2W2ldIDwtIHgkbHlyX3NvY19rZ20yW2ldCiAgICAgIH0gZWxzZSB7CiAgICAgICAgeCRseXJfc29jX2NtdHZbaV0gPC0geCRseXJfc29jX2tnbTJbaV0gKyB4JGx5cl9zb2NfY210dltpLTFdIAogICAgICB9CiAgICB9CiAgICByZXR1cm4oeCkKICB9KQogIHJldHVybih1bnNwbGl0KGxzLCBkZiRwcm9fbmFtZSkpCn0pCnNhdmUoc3JhLjIwMDEubHMsIGZpbGUgPSAic3JhLjIwMDEubHMuUkRhdGEiKQpgYGAKCmBgYHtyIHNwbGluZS1mbSwgaW5jbHVkZSA9IEZBTFNFfQojIyMgc3BsaW5lIGZpdCBmb3IgZm0KIyMgYnVsayAoc3BsaXQgYnkgcHJvIHJlcCkKIyAyMDAxCnNyYS4yMDAxLmZtLnNwIDwtIGxhcHBseShzcmEuMjAwMS5scywgZnVuY3Rpb24oZGYpIHsKICBsYXBwbHkoc3BsaXQoZGYsIGRmJHByb19uYW1lKSwgZnVuY3Rpb24oeCkgewogICAgZGVwdGhzKHgpIDwtIHByb19uYW1lIH4gbHlyX3RvcCArIGx5cl9ib3QKICAgIHgubXBzIDwtIG1wc3BsaW5lKHgsIHZhci5uYW1lID0gImZtIikKICAgIHgubXBzJHZhci4xY20gPC0geC5tcHMkdmFyLjFjbVsxOm1heCh4JGx5cl9ib3QpXQogICAgcmV0dXJuKHgubXBzKQogIH0pCn0pCiMgMjAwOQpzcmEuMjAwOS5mbS5zcCA8LSBsYXBwbHkoc3JhLjIwMDkubHMsIGZ1bmN0aW9uKHgpIHsKICBkZXB0aHMoeCkgPC0gcHJvX25hbWUgfiBseXJfdG9wICsgbHlyX2JvdAogIHgubXBzIDwtIG1wc3BsaW5lKHgsIHZhci5uYW1lID0gImx5cl9mcmFjdGlvbl9tb2Rlcm4iKQogIHgubXBzJHZhci4xY20gPC0geC5tcHMkdmFyLjFjbVsxOm1heCh4JGx5cl9ib3QpXQogIHJldHVybih4Lm1wcykKfSkKIyAyMDE5CnNyYS4yMDE5LmZtLnNwIDwtIGxhcHBseShzcmEuMjAxOS5scywgZnVuY3Rpb24oZGYpIHsKICBsYXBwbHkoc3BsaXQoZGYsIGRmJHByb19uYW1lKSwgZnVuY3Rpb24oeCkgewogICAgZGVwdGhzKHgpIDwtIHByb19uYW1lIH4gbHlyX3RvcCArIGx5cl9ib3QKICAgIHgubXBzIDwtIG1wc3BsaW5lKHgsIHZhci5uYW1lID0gImZtIikKICAgIHgubXBzJHZhci4xY20gPC0geC5tcHMkdmFyLjFjbVsxOm1heCh4JGx5cl9ib3QpXQogICAgcmV0dXJuKHgubXBzKQogIH0pCn0pCgojIyBpbmMKIyBuZWVkIG1pbiBhbmQgbWF4IHZhbHVlcyBmb3Igc3BsaW5lIGZpdHMKIyAyMDAxCnNyYS4yMDAxLmluYy5mbS5zcCA8LSBsYXBwbHkoc3JhLjIwMDEuaW5jLnN1bS5scywgZnVuY3Rpb24oZGYpIHsKICAgIGRlcHRocyhkZikgPC0gUE1lY28gfiBseXJfdG9wICsgbHlyX2JvdAogICAgbWVhbi5tcHMgPC0gbXBzcGxpbmUoZGYsIHZhci5uYW1lID0gImZtX21lYW4iKQogICAgbWluLm1wcyA8LSBtcHNwbGluZShkZiwgdmFyLm5hbWUgPSAiZm1fbCIpCiAgICBtYXgubXBzIDwtIG1wc3BsaW5lKGRmLCB2YXIubmFtZSA9ICJmbV91IikKICAgIHJldHVybihsaXN0KG1lYW4udmFyLjFjbSA9IG1lYW4ubXBzJHZhci4xY21bMTptYXgoZGYkbHlyX2JvdCldLAogICAgICAgICAgICAgICAgbWluLnZhci4xY20gPSBtaW4ubXBzJHZhci4xY21bMTptYXgoZGYkbHlyX2JvdCldLAogICAgICAgICAgICAgICAgbWF4LnZhci4xY20gPSBtYXgubXBzJHZhci4xY21bMTptYXgoZGYkbHlyX2JvdCldKSkKICB9KQojIDIwMTkKc3JhLjIwMTkuaW5jLmZtLnNwIDwtIGxhcHBseShzcmEuMjAxOS5pbmMuc3VtLmxzLCBmdW5jdGlvbihkZikgewogIGRmIDwtIGRmWy13aGljaChkZiRseXJfYm90ID09IDApLCBdCiAgZGVwdGhzKGRmKSA8LSBQTWVjbyB+IGx5cl90b3AgKyBseXJfYm90CiAgbWVhbi5tcHMgPC0gbXBzcGxpbmUoZGYsIHZhci5uYW1lID0gImZtX21lYW4iKQogIG1pbi5tcHMgPC0gbXBzcGxpbmUoZGYsIHZhci5uYW1lID0gImZtX2wiKQogIG1heC5tcHMgPC0gbXBzcGxpbmUoZGYsIHZhci5uYW1lID0gImZtX3UiKQogIHJldHVybihsaXN0KG1lYW4udmFyLjFjbSA9IG1lYW4ubXBzJHZhci4xY21bMTptYXgoZGYkbHlyX2JvdCldLAogICAgICAgICAgICAgIG1pbi52YXIuMWNtID0gbWluLm1wcyR2YXIuMWNtWzE6bWF4KGRmJGx5cl9ib3QpXSwKICAgICAgICAgICAgICBtYXgudmFyLjFjbSA9IG1heC5tcHMkdmFyLjFjbVsxOm1heChkZiRseXJfYm90KV0pKQp9KQpgYGAKCmBgYHtyIHNwbGluZS1iZC1zb2MtMTksIGluY2x1ZGUgPSBGQUxTRX0KIyBOZWVkIFNPQyBzdG9jayBkYXRhIGZvciAyMDE5IHNhbXBsZXM6IHVzZSBtYXNzIGRhdGEgZnJvbSAyMDA5IHNhbXBsZXMgCiMgc3BsaW5lIGZpdCBmb3IgY210diBtYXNzOyBzcGVjaWZ5IDEwY20gZGVwdGhzCnNyYS4yMDA5Lm1hc3Muc3AgPC0gbGFwcGx5KHNyYS4yMDA5LmxzLCBmdW5jdGlvbihkZikgewogIGRlcHRocyhkZikgPC0gcHJvX25hbWUgfiBseXJfdG9wICsgbHlyX2JvdAogIGRmLm1wcyA8LSBtcHNwbGluZShkZiwgdmFyLm5hbWUgPSAibWFzc19rZ20yIiwgZCA9IHNlcSgwLCBtYXgoZGYkbHlyX2JvdCksIGJ5ID0gMTApKQogIHJldHVybihkZi5tcHMpCn0pCgpzcmEuMjAwOS5iZC5zcCA8LSBsYXBwbHkoc3JhLjIwMDkubHMsIGZ1bmN0aW9uKGRmKSB7CiAgZGVwdGhzKGRmKSA8LSBwcm9fbmFtZSB+IGx5cl90b3AgKyBseXJfYm90CiAgZGYubXBzIDwtIG1wc3BsaW5lKGRmLCB2YXIubmFtZSA9ICJCRF9nX2NtXzMiLCBkID0gc2VxKDAsIG1heChkZiRseXJfYm90KSwgYnkgPSAxMCkpCiAgcmV0dXJuKGRmLm1wcykKfSkKCiMgY2FsY3VsYXRlIG1lYW4gb2YgMWNtIG1hc3MgcHJlZGljdGlvbnMgZm9yIGVhY2ggMjAxOSBkZXB0aCBpbmNyZW1lbnQKbWFzc19wcmVkIDwtIGxhcHBseShzZXFfYWxvbmcoc3JhLjIwMDkubWFzcy5zcCksIGZ1bmN0aW9uKGkpIHsKICBscyA8LSBzcGxpdChzcmEuMjAxOS5sc1tbaV1dLCBzcmEuMjAxOS5sc1tbaV1dWyJwcm9fcmVwIl0pICMgc3BsaXQgZWFjaCByZXBsaWNhdGUgcHJvZmlsZQogIGxzIDwtIGxhcHBseShscywgZnVuY3Rpb24oZGYpIHsKICAgIHQoc3JhLjIwMDkubWFzcy5zcFtbaV1dW1sidmFyLnN0ZCJdXSlbMTpucm93KGRmKV0gIyBtYXNzX2tnbTIKICAgIH0pCiAgcmV0dXJuKHVuc3BsaXQobHMsIHNyYS4yMDE5LmxzW1tpXV1bInByb19yZXAiXSkpCn0pCgojIGNhbGN1bGF0ZSBtZWFuIG9mIDFjbSBCRCBwcmVkaWN0aW9ucyBmb3IgZWFjaCAyMDE5IGRlcHRoIGluY3JlbWVudApiZF9wcmVkIDwtIGxhcHBseShzZXFfYWxvbmcoc3JhLjIwMDkuYmQuc3ApLCBmdW5jdGlvbihpKSB7CiAgbHMgPC0gc3BsaXQoc3JhLjIwMTkubHNbW2ldXSwgc3JhLjIwMTkubHNbW2ldXVsicHJvX3JlcCJdKSAjIHNwbGl0IGVhY2ggcmVwbGljYXRlIHByb2ZpbGUKICBscyA8LSBsYXBwbHkobHMsIGZ1bmN0aW9uKGRmKSB7CiAgICB0KHNyYS4yMDA5LmJkLnNwW1tpXV1bWyJ2YXIuc3RkIl1dKVsxOm5yb3coZGYpXSAjIG1hc3Nfa2dtMgogICAgfSkKICByZXR1cm4odW5zcGxpdChscywgc3JhLjIwMTkubHNbW2ldXVsicHJvX3JlcCJdKSkKfSkKCiMgbWVyZ2UgcHJlZGljdGVkIG1hc3MgdmFsdWVzIHdpdGggc3JhLjIwMTkubHMKbm1zIDwtIG5hbWVzKHNyYS4yMDE5LmxzKQpzcmEuMjAxOS5scyA8LSBsYXBwbHkoc2VxX2Fsb25nKHNyYS4yMDE5LmxzKSwgZnVuY3Rpb24oZGYpIHsKICBjYmluZChzcmEuMjAxOS5sc1tbZGZdXSwgYmRfZ19jbTMgPSBiZF9wcmVkW1tkZl1dKQp9KQpuYW1lcyhzcmEuMjAxOS5scykgPC0gbm1zCgojIGFkZCBjIGNvbmMKc3JhLjIwMTkubHMgPC0gbGFwcGx5KHNyYS4yMDE5LmxzLCBmdW5jdGlvbihkZikgewogIGRmJGRlcHRoIDwtIHBhc3RlMChkZiRseXJfdG9wLCAiLSIsIGRmJGx5cl9ib3QpCiAgZGYgPC0gbWVyZ2UoZGYsIGVsbV9yZXN1bHRzX2RmWyAsIGMoIlBNZWNvIiwgInByb19yZXAiLCAiZGVwdGgiLCAiQyIsICJOIildLCBieSA9IGMoIlBNZWNvIiwgImRlcHRoIiwgInByb19yZXAiKSkKICByZXR1cm4oZGYpCn0pCgojIyBjYWxjdWxhdGUgc3RvY2tzIGFuZCBjdW11bGF0aXZlIHN0b2Nrcwpjc3RvY2suZnggPC0gZnVuY3Rpb24obHMsIG1hc3MsIGJkLCBDKSB7CiAgbGFwcGx5KGxzLCBmdW5jdGlvbihkZikgewogICAgaWYgKGlzLm5hKG1hc3MpKSB7CiAgICAgZGYkbHlyX3NvYyA8LSBkZltbYmRdXSAqIGRmW1tDXV0gKiAoZGYkbHlyX2JvdCAtIGRmJGx5cl90b3ApICogMTBeLTEgCiAgICB9IGVsc2UgewogICAgIGRmJGx5cl9zb2MgPC0gZGZbW21hc3NdXSAqIGRmW1tDXV0gKiAxMF4tMiAKICAgIH0KICAgIHByb19scyA8LSBzcGxpdChkZiwgZGYkcHJvX25hbWUpCiAgICBwcm9fbHMgPC0gbGFwcGx5KHByb19scywgZnVuY3Rpb24oeCkgewogICAgICB4JGx5cl9zb2NfY210diA8LSBOQQogICAgICBmb3IoaSBpbiBzZXFfYWxvbmcoeCRseXJfYm90KSkgewogICAgICAgIGlmKGkgPT0gMSkgewogICAgICAgICAgeCRseXJfc29jX2NtdHZbaV0gPC0geCRseXJfc29jW2ldCiAgICAgICAgfSBlbHNlIHsKICAgICAgICAgIHgkbHlyX3NvY19jbXR2W2ldIDwtIHgkbHlyX3NvY1tpXSArIHgkbHlyX3NvY19jbXR2W2ktMV0gCiAgICAgICAgfQogICAgICB9CiAgICAgIHJldHVybih4KQogICAgfSkKICAgIHJldHVybih1bnNwbGl0KHByb19scywgZGYkcHJvX25hbWUpKQogIH0pCn0KIyAyMDE5CnNyYS4yMDE5LmxzIDwtIGNzdG9jay5meChzcmEuMjAxOS5scywgbWFzcyA9IE5BLCBiZCA9ICJiZF9nX2NtMyIsICJDIikKIyAyMDA5CnNyYS4yMDA5LmxzIDwtIGNzdG9jay5meChzcmEuMjAwOS5scywgIm1hc3Nfa2dtMiIsIGJkID0gTkEsICJDX3BjdCIpCgojIHNhdmUKc2F2ZShzcmEuMjAxOS5scywgZmlsZSA9ICJzcmEuMjAxOS5scy5SRGF0YSIpCiMgd3JpdGUuY3N2KGJpbmRfcm93cyhzcmEuMjAxOS5scyksIGZpbGUgPSAic3JhLjIwMTkuZGYuY3N2IikKCiMgbWFrZSBkZgpzcmEuMjAxOS5zdW0uZGYgPC0gYmluZF9yb3dzKAogIGxhcHBseShzcmEuMjAxOS5scywgZnVuY3Rpb24oZGYpIHsKICAgIGRmICU+JQogICAgICBncm91cF9ieShQTWVjbywgbHlyX3RvcCwgbHlyX2JvdCkgJT4lCiAgICAgIHN1bW1hcml6ZShhY3Jvc3MoYyhmbSwgYmRfZ19jbTMsIEMsIE4sIGx5cl9zb2MpLCAuZm5zID0gbGlzdChtZWFuID0gbWVhbiwgc2QgPSBzZCkpKSAlPiUKICAgICAgc2VsZWN0KC1iZF9nX2NtM19zZCkgJT4lCiAgICAgIGRhdGEuZnJhbWUKICB9KQogICwgLmlkID0gIlBNZWNvIikKIyB3cml0ZS5jc3Yoc3JhLjIwMTkuc3VtLmRmLCBmaWxlID0gIi9Vc2Vycy9qZWZmL0Rlc2t0b3Avc3JhLjIwMTkuc3VtLmNzdiIpCmBgYAoKYGBge3Igc3BsaW5lLXNvYywgaW5jbHVkZSA9IEZBTFNFfQojIHNwbGluZSBmaXQgZm9yIGNhcmJvbiBzdG9ja3MgKGZvciBjYWxjIHdlaWdodGVkIGF2ZXJhZ2VzKQpkZXB0aC5zcGxpbmUgPC0gZnVuY3Rpb24oeCkgewogIHNwIDwtIHNwbGluZSh4LCBtZXRob2QgPSAiaHltYW4iKSAjIGZpdCBtb25vdG9uaWMgY3ViaWMgc3BsaW5lCiAgc3Auc3MgPC0gc21vb3RoLnNwbGluZShzcCkgIyBjb252ZXJ0IHRvIGNsYXNzICJzcGxpbmUiIHdpdGggc21vb3RoLnNwbGluZSBmeG4KICBzdGQgPC0gc2VxKDAsIDEwMCkgIyBpbiBjbSAobGluZWFyIGJleW9uZCBsYXN0IG1lYXN1cmVkIGRlcHRoKQogIHNwIDwtIHByZWRpY3Qoc3Auc3MsIHN0ZCkgCiAgZGYgPC0gZGF0YS5mcmFtZShzcCkKICBjb2xuYW1lcyhkZikgPC0gYygibHlyX2JvdCIsImx5cl9zb2MiKSAjIHdoZXJlIGx5cl9zb2MgPSBjdW11bGF0aXZlIFNPQyBpbiBvdXRwdXQKICBmb3IoaSBpbiBzZXFfYWxvbmcoZGYkbHlyX2JvdCkpIHsKICAgIGlmKGkgPT0gMSkgewogICAgICBkZiRseXJfc29jW2ldIDwtIGRmJGx5cl9zb2NbaV0KICAgIH0gZWxzZSB7CiAgICAgIGRmJGx5cl9zb2NbaV0gPC0gZGYkbHlyX3NvY1tpICsgMV0gLSBkZiRseXJfc29jW2ldCiAgICB9CiAgfQogIGRmIDwtIGRmWy0xLF0KICByZXR1cm4oZGZbLWxlbmd0aChkZiRseXJfc29jKSwgXSkKfQoKIyMgYWRkICgwLCAwKSBwb2ludCBmb3IgKGx5cl9ib3QsIGx5cl9jbXR2X3N0b2NrKQojIDIwMDEKc3JhLjIwMDEuc3AubHMgPC0gbGFwcGx5KHNyYS4yMDAxLmxzLCBmdW5jdGlvbihkZikgewogIGxzIDwtIGxhcHBseShzcGxpdChkZiwgZGYkcHJvX25hbWUpLCBmdW5jdGlvbih4KSB7CiAgICB0MCA8LSBkYXRhLmZyYW1lKG1hdHJpeChucm93ID0gMSwgbmNvbCA9IG5jb2woeCkpKQogICAgeHkgPC0gYyh3aGljaChuYW1lcyh4KSA9PSAibHlyX2JvdCIpLCB3aGljaChuYW1lcyh4KSA9PSAibHlyX3NvY19jbXR2IikpCiAgICB0MFsgLCB4eV0gPC0gMAogICAgbmFtZXModDApIDwtIG5hbWVzKHgpCiAgICB0MCRwcm9fbmFtZSA8LSB1bmlxdWUoeCRwcm9fbmFtZSkKICAgIHJldHVybihyYmluZCh0MCwgeCkpCiAgfSkKICByZXR1cm4oYmluZF9yb3dzKGxzKSkKfSkKc3JhLjIwMDEuc3AubHMuYXZnIDwtIGxhcHBseShzcmEuMjAwMS5zdW0ubHMyLCBmdW5jdGlvbihkZikgewogIHh5IDwtIGRmWyAsIGMoImx5cl9ib3QiLCAibHlyX3NvY19jbXR2IildCiAgdDAgPC0gZGF0YS5mcmFtZShseXJfYm90ID0gMCwgbHlyX3NvY19jbXR2ID0gMCkKICByZXR1cm4ocmJpbmQodDAsIHh5KSkKfSkKIyAyMDA5CnNyYS4yMDA5LnNwLmxzIDwtIGxhcHBseShzcmEuMjAwOS5scywgZnVuY3Rpb24oZGYpIHsKICB0MCA8LSBkYXRhLmZyYW1lKG1hdHJpeChucm93ID0gMSwgbmNvbCA9IG5jb2woZGYpKSkKICB4eSA8LSBjKHdoaWNoKG5hbWVzKGRmKSA9PSAibHlyX2JvdCIpLCB3aGljaChuYW1lcyhkZikgPT0gImx5cl9zb2NfY210diIpKQogIHQwWyAsIHh5XSA8LSAwCiAgbmFtZXModDApIDwtIG5hbWVzKGRmKQogIG5ldyA8LSByYmluZCh0MCwgZGYpCiAgcmV0dXJuKG5ldykKfSkKIyAyMDE5CnNyYS4yMDE5LnNwLmxzIDwtIGxhcHBseShzcmEuMjAxOS5scywgZnVuY3Rpb24oZGYpIHsKICBscyA8LSBsYXBwbHkoc3BsaXQoZGYsIGRmJHByb19uYW1lKSwgZnVuY3Rpb24oeCkgewogICAgdDAgPC0gZGF0YS5mcmFtZShtYXRyaXgobnJvdyA9IDEsIG5jb2wgPSBuY29sKHgpKSkKICAgIHh5IDwtIGMod2hpY2gobmFtZXMoeCkgPT0gImx5cl9ib3QiKSwgd2hpY2gobmFtZXMoeCkgPT0gImx5cl9zb2NfY210diIpKQogICAgdDBbICwgeHldIDwtIDAKICAgIG5hbWVzKHQwKSA8LSBuYW1lcyh4KQogICAgdDAkcHJvX25hbWUgPC0gdW5pcXVlKHgkcHJvX25hbWUpCiAgICByZXR1cm4ocmJpbmQodDAsIHgpKQogIH0pCiAgcmV0dXJuKGJpbmRfcm93cyhscykpCn0pCgojIyBydW4gc3BsaW5lCiMgMjAwMQpzcmEuMjAwMS5vYy5zcCA8LSBsYXBwbHkoc3JhLjIwMDEuc3AubHMsIGZ1bmN0aW9uKGRmKSB7CiAgbGFwcGx5KHNwbGl0KGRmLCBkZiRwcm9fbmFtZSksIGZ1bmN0aW9uKHgpIHsKICAgIGRlcHRoLnNwbGluZSh4WywgYygibHlyX2JvdCIsICJseXJfc29jX2NtdHYiKV0pCiAgfSkKfSkKc3JhLjIwMDEub2Muc3AuYXZnIDwtIGxhcHBseShzcmEuMjAwMS5zcC5scy5hdmcsIGZ1bmN0aW9uKGRmKSB7CiAgZGVwdGguc3BsaW5lKGRmKQp9KQojIDIwMDkKc3JhLjIwMDkub2Muc3AgPC0gbGFwcGx5KHNyYS4yMDA5LnNwLmxzLCBmdW5jdGlvbih4KSB7CiAgZGVwdGguc3BsaW5lKHhbLCBjKCJseXJfYm90IiwgImx5cl9zb2NfY210diIpXSkKfSkKIyAyMDE5CnNyYS4yMDE5Lm9jLnNwIDwtIGxhcHBseShzcmEuMjAxOS5zcC5scywgZnVuY3Rpb24oZGYpIHsKICBsYXBwbHkoc3BsaXQoZGYsIGRmJHByb19uYW1lKSwgZnVuY3Rpb24oeCkgewogICAgZGVwdGguc3BsaW5lKHhbLCBjKCJseXJfYm90IiwgImx5cl9zb2NfY210diIpXSkKICB9KQp9KQpzcmEuMjAxOS5vYy5zcC5hdmcgPC0gbGFwcGx5KHNyYS4yMDE5Lm9jLnNwLCBmdW5jdGlvbihscykgewogIGJpbmRfcm93cyhscykgJT4lCiAgICBncm91cF9ieShseXJfYm90KSAlPiUKICAgIHN1bW1hcml6ZShseXJfc29jID0gbWVhbihseXJfc29jKSkgJT4lCiAgICBkYXRhLmZyYW1lCn0pCmBgYAoKYGBge3IgcGxvdC1zb2MtY210dn0KIyAyMDAxCnNyYS4yMDAxLnNvYy5kZiA8LSBiaW5kX3Jvd3MobGFwcGx5KHNlcV9hbG9uZyhzcmEuMjAwMS5vYy5zcC5hdmcpLCBmdW5jdGlvbihpKSB7CiAgTk0gPC0gbmFtZXMoc3JhLjIwMDEub2Muc3AuYXZnKVtpXQogIFBNIDwtIHN1YnN0cihOTSwgMSwgMikKICBFQ08gPC0gc3Vic3RyKE5NLCAzLCA0KQogIGRmIDwtIGRhdGEuZnJhbWUoUE0gPSBQTSwgRUNPID0gRUNPLCBseXJfc29jXzMwID0gc3VtKHNyYS4yMDAxLm9jLnNwLmF2Z1tbaV1dWzE6MzAsICJseXJfc29jIl0pKQogIGRmJEVDTyA8LSBmYWN0b3IoZGYkRUNPLCBsZXZlbHMgPSBjKCJwcCIsICJ3ZiIsICJyZiIpKQogIHJldHVybihkZikKfSkpCgojIDIwMDkKc3JhLjIwMDkuc29jLmRmIDwtIGJpbmRfcm93cyhsYXBwbHkoc2VxX2Fsb25nKHNyYS4yMDA5Lm9jLnNwKSwgZnVuY3Rpb24oaSkgewogIE5NIDwtIG5hbWVzKHNyYS4yMDA5Lm9jLnNwKVtpXQogIFBNIDwtIHN1YnN0cihOTSwgMSwgMikKICBFQ08gPC0gc3Vic3RyKE5NLCAzLCA0KQogIGRmIDwtIGRhdGEuZnJhbWUoUE0gPSBQTSwgRUNPID0gRUNPLCBseXJfc29jXzMwID0gc3VtKHNyYS4yMDA5Lm9jLnNwW1tpXV1bMTozMCwgImx5cl9zb2MiXSkpCiAgZGYkRUNPIDwtIGZhY3RvcihkZiRFQ08sIGxldmVscyA9IGMoInBwIiwgIndmIiwgInJmIikpCiAgcmV0dXJuKGRmKQp9KSkKCiMgMjAxOQpzcmEuMjAxOS5zb2MuZGYgPC0gYmluZF9yb3dzKGxhcHBseShzZXFfYWxvbmcoc3JhLjIwMTkub2Muc3AuYXZnKSwgZnVuY3Rpb24oaSkgewogIE5NIDwtIG5hbWVzKHNyYS4yMDE5Lm9jLnNwLmF2ZylbaV0KICBQTSA8LSBzdWJzdHIoTk0sIDEsIDIpCiAgRUNPIDwtIHN1YnN0cihOTSwgMywgNCkKICBkZiA8LSBkYXRhLmZyYW1lKFBNID0gUE0sIEVDTyA9IEVDTywgbHlyX3NvY18zMCA9IHN1bShzcmEuMjAxOS5vYy5zcC5hdmdbW2ldXVsxOjMwLCAibHlyX3NvYyJdKSkKICBkZiRFQ08gPC0gZmFjdG9yKGRmJEVDTywgbGV2ZWxzID0gYygicHAiLCAid2YiLCAicmYiKSkKICByZXR1cm4oZGYpCn0pKQoKZ2dwbG90KHNyYS4yMDE5LnNvYy5kZiwgYWVzKFBNLCBseXJfc29jXzMwLCBmaWxsID0gUE0pKSArCiAgZ2VvbV9jb2wocG9zaXRpb24gPSAiZG9kZ2UiKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiQU4iID0gYW5kZXNpdGUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkJTIiA9IGJhc2FsdCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJHUiIgPSBncmFuaXRlKSkgKwogIGZhY2V0X2dyaWQoY29scyA9IHZhcnMoRUNPKSkgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKHBhbmVsLmdyaWQgPSBlbGVtZW50X2JsYW5rKCkpCgpnZ3Bsb3Qoc3JhLjIwMDkuc29jLmRmLCBhZXMoUE0sIGx5cl9zb2NfMzAsIGZpbGwgPSBQTSkpICsKICBnZW9tX2NvbChwb3NpdGlvbiA9ICJkb2RnZSIpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJBTiIgPSBhbmRlc2l0ZSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQlMiID0gYmFzYWx0LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkdSIiA9IGdyYW5pdGUpKSArCiAgZmFjZXRfZ3JpZChjb2xzID0gdmFycyhFQ08pKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUocGFuZWwuZ3JpZCA9IGVsZW1lbnRfYmxhbmsoKSkKCmdncGxvdChzcmEuMjAwMS5zb2MuZGYsIGFlcyhQTSwgbHlyX3NvY18zMCwgZmlsbCA9IFBNKSkgKwogIGdlb21fY29sKHBvc2l0aW9uID0gImRvZGdlIikgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIkFOIiA9IGFuZGVzaXRlLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJCUyIgPSBiYXNhbHQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiR1IiID0gZ3Jhbml0ZSkpICsKICBmYWNldF9ncmlkKGNvbHMgPSB2YXJzKEVDTykpICsKICB0aGVtZV9idygpICsKICB0aGVtZShwYW5lbC5ncmlkID0gZWxlbWVudF9ibGFuaygpKQoKIyBhbGwgdG9nZXRoZXIKc3JhLjAxLjA5LjE5LnNvYy5kZiA8LSBjYmluZChyYmluZChzcmEuMjAwMS5zb2MuZGYsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3JhLjIwMDkuc29jLmRmLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNyYS4yMDE5LnNvYy5kZiksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHllYXIgPSByZXAoYygyMDAxLCAyMDA5LCAyMDE5KSwgZWFjaCA9IDkpKQpzcmEuMDEuMDkuMTkuc29jLmRmICU+JQogIG11dGF0ZShQTXllYXIgPSBwYXN0ZTAoUE0sIHllYXIpKSAlPiUKICBnZ3Bsb3QoLiwgYWVzKFBNeWVhciwgbHlyX3NvY18zMCwgZmlsbCA9IFBNLCBhbHBoYSA9IHllYXIpKSArCiAgZ2VvbV9jb2wocG9zaXRpb24gPSAiZG9kZ2UiKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiQU4iID0gYW5kZXNpdGUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkJTIiA9IGJhc2FsdCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJHUiIgPSBncmFuaXRlKSkgKwogIGZhY2V0X2dyaWQoY29scyA9IHZhcnMoRUNPKSkgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKHBhbmVsLmdyaWQgPSBlbGVtZW50X2JsYW5rKCkpCmBgYAoKYGBge3IgY3d0LWQxNGMtMDEsIGluY2x1ZGUgPSBGQUxTRX0KIyMgY2FsY3VsYXRlIHN0b2NrIHdlaWdodHMKIyMgMjAwMSBkZXB0aHMKIyBvcmRlciAnMDEgZGF0YQpzcmEuMjAwMS5zdW0ubHMgPC0gbGFwcGx5KHNyYS4yMDAxLnN1bS5scywgZnVuY3Rpb24oZGYpIGRmW29yZGVyKGRmJGx5cl9ib3QpLCBdKQojIDIwMDkKY3d0LjAxLjA5IDwtIGxhcHBseShzZXFfYWxvbmcoc3JhLjIwMDkub2Muc3ApLCBmdW5jdGlvbihpKSB7CiAgZCA8LSBzcmEuMjAwMS5zdW0ubHNbW2ldXVtbImx5cl9ib3QiXV0gIyBtYXAgb250byAnMDEgZGVwdGhzCiAgYyA8LSB2ZWN0b3IobW9kZSA9ICJsaXN0IiwgbGVuZ3RoID0gbGVuZ3RoKGQpKQogIGZvcihqIGluIHNlcV9hbG9uZyhkKSkgewogICAgaWYoaiA9PSAxKSB7CiAgICAgIGNbW2pdXSA8LSBzcmEuMjAwOS5vYy5zcFtbaV1dWzE6ZFtqXSwgImx5cl9zb2MiXQogICAgfSBlbHNlIHsKICAgICAgY1tbal1dIDwtIHNyYS4yMDA5Lm9jLnNwW1tpXV1bKGRbai0xXSsxKTpkW2pdLCAibHlyX3NvYyJdIAogICAgfQogIH0KICByZXR1cm4odW5saXN0KGxhcHBseShjLCBmdW5jdGlvbih4KSB4L3N1bSh4KSkpKSAjIHJldHVybiB3ZWlnaHRzCn0pCm5hbWVzKGN3dC4wMS4wOSkgPC0gbmFtZXMoc3JhLjIwMDkub2Muc3ApCiMgMjAxOSAoc2Vjb25kIGxpc3QgbGV2ZWwgZnJvbSBwcm9maWxlIHJlcHMpCmN3dC4wMS4xOSA8LSBsYXBwbHkoc2VxX2Fsb25nKHNyYS4yMDE5Lm9jLnNwKSwgZnVuY3Rpb24oaSkgewogIGxhcHBseShzcmEuMjAxOS5vYy5zcFtbaV1dLCBmdW5jdGlvbihkZikgewogICAgZCA8LSBzcmEuMjAwMS5zdW0ubHNbW2ldXVtbImx5cl9ib3QiXV0gIyBtYXAgb250byAnMDEgZGVwdGhzCiAgICBjIDwtIHZlY3Rvcihtb2RlID0gImxpc3QiLCBsZW5ndGggPSBsZW5ndGgoZCkpCiAgICBmb3IoaiBpbiBzZXFfYWxvbmcoZCkpIHsKICAgICAgaWYoaiA9PSAxKSB7CiAgICAgICAgY1tbal1dIDwtIGRmWzE6ZFtqXSwgImx5cl9zb2MiXQogICAgICB9IGVsc2UgewogICAgICAgIGNbW2pdXSA8LSBkZlsoZFtqLTFdKzEpOmRbal0sICJseXJfc29jIl0gCiAgICAgIH0KICAgIH0KICAgIHJldHVybih1bmxpc3QobGFwcGx5KGMsIGZ1bmN0aW9uKHgpIHgvc3VtKHgpKSkpICAjIHJldHVybiB3ZWlnaHRzCiAgfSkKfSkKbmFtZXMoY3d0LjAxLjE5KSA8LSBuYW1lcyhzcmEuMjAxOS5vYy5zcCkKIyBhdmVyYWdlIGN3dCAnMTkgc2FtcGxlcywgJzAxIGRlcHRocwpjd3QuMDEuMTkuYXZnIDwtIGxhcHBseShzZXFfYWxvbmcoc3JhLjIwMTkub2Muc3AuYXZnKSwgZnVuY3Rpb24oaSkgewogICAgZCA8LSBzcmEuMjAxOS5zdW0ubHNbW2ldXVtbImx5cl9ib3QiXV0KICAgIGMgPC0gdmVjdG9yKG1vZGUgPSAibGlzdCIsIGxlbmd0aCA9IGxlbmd0aChkKSkKICAgIGZvcihqIGluIHNlcV9hbG9uZyhkKSkgewogICAgICBpZihqID09IDEpIHsKICAgICAgICBjW1tqXV0gPC0gc3JhLjIwMDEub2Muc3AuYXZnW1tpXV1bMTpkW2pdLCAibHlyX3NvYyJdCiAgICAgIH0gZWxzZSB7CiAgICAgICAgY1tbal1dIDwtIHNyYS4yMDAxLm9jLnNwLmF2Z1tbaV1dWyhkW2otMV0rMSk6ZFtqXSwgImx5cl9zb2MiXSAKICAgICAgfQogICAgfQogICAgcmV0dXJuKHVubGlzdChsYXBwbHkoYywgZnVuY3Rpb24oeCkgeC9zdW0oeCkpKSkKfSkKbmFtZXMoY3d0LjAxLjE5LmF2ZykgPC0gbmFtZXMoc3JhLjIwMTkub2Muc3ApCgojIyBjYWxjdWxhdGUgZm1fd3RzCiMjICcwMSBkZXB0aHMKIyAyMDE5CmZtLnd0LjAxLjE5IDwtIGxhcHBseShzZXFfYWxvbmcoY3d0LjAxLjE5KSwgZnVuY3Rpb24oaSkgewogIGxhcHBseShzZXFfYWxvbmcoY3d0LjAxLjE5W1tpXV0pLCBmdW5jdGlvbihqKSB7CiAgICBkZiA8LSBkYXRhLmZyYW1lKGN3dCA9IGN3dC4wMS4xOVtbaV1dW1tqXV0pCiAgICBkZiRmbSA8LSBzcmEuMjAxOS5mbS5zcFtbaV1dW1tqXV1bWyJ2YXIuMWNtIl1dWzE6bGVuZ3RoKGN3dC4wMS4xOVtbaV1dW1tqXV0pXQogICAgZGYkZm1fd3QgPC0gZGYkZm0gKiBkZiRjd3QKICByZXR1cm4oZGYpCiAgfSkKfSkgCm5hbWVzKGZtLnd0LjAxLjE5KSA8LSBuYW1lcyhjd3QuMDEuMTkpCgojIDIwMDkKZm0ud3QuMDEuMDkgPC0gbGFwcGx5KHNlcV9hbG9uZyhjd3QuMDEuMDkpLCBmdW5jdGlvbihpKSB7CiAgZGYgPC0gZGF0YS5mcmFtZShjd3QgPSBjd3QuMDEuMDlbW2ldXSkKICBkZiRmbSA8LSBzcmEuMjAwOS5mbS5zcFtbaV1dW1sidmFyLjFjbSJdXVsxOmxlbmd0aChjd3QuMDEuMDlbW2ldXSldCiAgZGYkZm1fd3QgPC0gZGYkZm0gKiBkZiRjd3QKICByZXR1cm4oZGYpCn0pCm5hbWVzKGZtLnd0LjAxLjA5KSA8LSBuYW1lcyhjd3QuMDEuMDkpCgoKIyMgY2FsY3VsYXRlIHdlaWdodGVkIGF2ZXJhZ2Ugb2YgZm0gZm9yIGVhY2ggaW50ZXJ2YWwKIyMgJzAxIGRlcHRocwojIDIwMDkKc3JhLjAxLjA5LmxzIDwtIGxhcHBseShzZXFfYWxvbmcoc3JhLjIwMDEuc3VtLmxzKSwgZnVuY3Rpb24oaSkgewogIGQgPC0gc3JhLjIwMDEuc3VtLmxzW1tpXV1bWyJseXJfYm90Il1dCiAgZiA8LSB2ZWN0b3IobW9kZSA9ICJsaXN0IiwgbGVuZ3RoID0gbGVuZ3RoKGQpKQogIGZvcihqIGluIHNlcV9hbG9uZyhkKSkgewogICAgaWYoaiA9PSAxKSB7CiAgICAgIGZbW2pdXSA8LSBzdW0oZm0ud3QuMDEuMDlbW2ldXVsxOmRbal0sICJmbV93dCJdKQogICAgfSBlbHNlIHsKICAgICAgZltbal1dIDwtIHN1bShmbS53dC4wMS4wOVtbaV1dWyhkW2otMV0rMSk6ZFtqXSwgImZtX3d0Il0pCiAgICB9CiAgfQogIHJldHVybihjYmluZChzcmEuMjAwMS5zdW0ubHNbW2ldXSwgZm1fMDkgPSB1bmxpc3QoZikpKQp9KQpuYW1lcyhzcmEuMDEuMDkubHMpIDwtIG5hbWVzKGZtLnd0LjAxLjA5KQojIDIwMTkKc3JhLjAxLjE5LmxzIDwtIGZtLnd0LjAxLjE5ICMgaW5pdGlhbGl6ZSBsaXN0IHdpdGggZm0gd3Qgc3RydWN0dXJlCnNyYS4wMS4xOS5scyA8LSBsYXBwbHkoc2VxX2Fsb25nKHNyYS4yMDAxLnN1bS5scyksIGZ1bmN0aW9uKGkpIHsKICBzcmEuMDEuMTkubHNbW2ldXSA8LSBsYXBwbHkoc2VxX2Fsb25nKGZtLnd0LjAxLjE5W1tpXV0pLCBmdW5jdGlvbih4KSB7CiAgICBkIDwtIHNyYS4yMDAxLnN1bS5sc1tbaV1dW1sibHlyX2JvdCJdXQogICAgZiA8LSB2ZWN0b3IobW9kZSA9ICJsaXN0IiwgbGVuZ3RoID0gbGVuZ3RoKGQpKQogICAgZm9yKGogaW4gc2VxX2Fsb25nKGQpKSB7CiAgICAgIGlmKGogPT0gMSkgewogICAgICAgIGZbW2pdXSA8LSBzdW0oZm0ud3QuMDEuMTlbW2ldXVtbeF1dWzE6ZFtqXSwgImZtX3d0Il0pCiAgICAgIH0gZWxzZSB7CiAgICAgICAgZltbal1dIDwtIHN1bShmbS53dC4wMS4xOVtbaV1dW1t4XV1bKGRbai0xXSsxKTpkW2pdLCAiZm1fd3QiXSkKICAgICAgfQogICAgfQogICAgcmV0dXJuKHVubGlzdChmKSkgCiAgfSkKICBmbSA8LSBsYXBwbHkoc2VxX2Fsb25nKHNyYS4wMS4xOS5sc1tbaV1dW1sxXV0pLCBmdW5jdGlvbih6KSB7CiAgICBkYXRhLmZyYW1lKGZtXzE5X21lYW4gPSBtZWFuKHNhcHBseShzcmEuMDEuMTkubHNbW2ldXSwgIlsiLCB6KSwgbmEucm0gPSBUUlVFKSwKICAgICAgICAgICAgICAgZm1fMTlfc2QgPSBzZChzYXBwbHkoc3JhLjAxLjE5LmxzW1tpXV0sICJbIiwgeiksIG5hLnJtID0gVFJVRSkpCiAgICB9KQogIGZtIDwtIGJpbmRfcm93cyhmbSkKICByZXR1cm4oZm0pCn0pCnNyYS4wMS4wOS4xOS5scyA8LSBsYXBwbHkoc2VxX2Fsb25nKHNyYS4wMS4wOS5scyksIGZ1bmN0aW9uKGkpIHsKICBkYXRhLmZyYW1lKHNyYS4wMS4wOS5sc1tbaV1dLCBzcmEuMDEuMTkubHNbW2ldXSkKfSkKbmFtZXMoc3JhLjAxLjA5LjE5LmxzKSA8LSBuYW1lcyhzcmEuMDEuMDkubHMpCgojIyBjcmVhdGUgdGlkeSBjb21iaW5lZCAnMDEsICcwOSwgJzE5IGRhdGEgZnJhbWUKbm1zIDwtIGMoIlBNIiwgIkVDTyIsICJQTWVjbyIsICJseXJfdG9wIiwgImx5cl9ib3QiLCAiZm0iLCAiZm1fc2QiKQpzcmEuMDEuMDkuMTkuZGYgPC0gYmluZF9yb3dzKHNyYS4wMS4wOS4xOS5scykKc3JhLjAxLjA5LjE5IDwtIHNyYS4wMS4wOS4xOS5kZlssIG5tc10Kc3JhLjAxLjA5LjE5IDwtIHJiaW5kKGNiaW5kKHNyYS4wMS4wOS4xOSwgWWVhciA9IGFzLmNoYXJhY3RlcigyMDAxKSksCiAgICAgICAgICAgICAgICAgICAgICBkYXRhLmZyYW1lKHNyYS4wMS4wOS4xOVssIG5tc1sxOjVdXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZm0gPSBzcmEuMDEuMDkuMTkuZGYkZm1fMDksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZtX3NkID0gTkEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFllYXIgPSBhcy5jaGFyYWN0ZXIoMjAwOSkpLAogICAgICAgICAgICAgICAgICAgICAgZGF0YS5mcmFtZShzcmEuMDEuMDkuMTlbLCBubXNbMTo1XV0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZtID0gc3JhLjAxLjA5LjE5LmRmJGZtXzE5X21lYW4sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZtX3NkID0gc3JhLjAxLjA5LjE5LmRmJGZtXzE5X3NkLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBZZWFyID0gYXMuY2hhcmFjdGVyKDIwMTkpKSkKCiMgY2FsYyBkMTRjIGZyb20gZm0Kc3JhLjAxLjA5LjE5JGQxNGMgPC0gY2FsY18xNGMoc3JhLjAxLjA5LjE5JGZtLCBhcy5udW1lcmljKGFzLmNoYXJhY3RlcihzcmEuMDEuMDkuMTkkWWVhcikpKQpzcmEuMDEuMDkuMTkkZDE0Y19zZCA8LSBhYnMoc3JhLjAxLjA5LjE5JGQxNGMgLSBjYWxjXzE0YyhzcmEuMDEuMDkuMTkkZm0gKyBzcmEuMDEuMDkuMTkkZm1fc2QsIGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKHNyYS4wMS4wOS4xOSRZZWFyKSkpKQpgYGAKCmBgYHtyIGN3dC1kMTRjLTE5LCBpbmNsdWRlID0gRkFMU0V9CiMjIGNhbGN1bGF0ZSBzdG9jayB3ZWlnaHRzCiMjIDIwMTkgZGVwdGhzCiMgMjAwMQpjd3QuMTkuMDEgPC0gbGFwcGx5KHNlcV9hbG9uZyhzcmEuMjAwMS5vYy5zcCksIGZ1bmN0aW9uKGkpIHsKICBsYXBwbHkoc3JhLjIwMDEub2Muc3BbW2ldXSwgZnVuY3Rpb24oZGYpIHsKICAgIGQgPC0gc3JhLjIwMTkuc3VtLmxzW1tpXV1bWyJseXJfYm90Il1dCiAgICBjIDwtIHZlY3Rvcihtb2RlID0gImxpc3QiLCBsZW5ndGggPSBsZW5ndGgoZCkpCiAgICBmb3IoaiBpbiBzZXFfYWxvbmcoZCkpIHsKICAgICAgaWYoaiA9PSAxKSB7CiAgICAgICAgY1tbal1dIDwtIGRmWzE6ZFtqXSwgImx5cl9zb2MiXQogICAgICB9IGVsc2UgewogICAgICAgIGNbW2pdXSA8LSBkZlsoZFtqLTFdKzEpOmRbal0sICJseXJfc29jIl0gCiAgICAgIH0KICAgIH0KICAgIHJldHVybih1bmxpc3QobGFwcGx5KGMsIGZ1bmN0aW9uKHgpIHgvc3VtKHgpKSkpCiAgfSkKfSkKbmFtZXMoY3d0LjE5LjAxKSA8LSBuYW1lcyhzcmEuMjAwMS5vYy5zcCkKIyAyMDAxIG1lYW4KY3d0LjE5LjAxLmF2ZyA8LSBsYXBwbHkoc2VxX2Fsb25nKHNyYS4yMDAxLm9jLnNwLmF2ZyksIGZ1bmN0aW9uKGkpIHsKICAgIGQgPC0gc3JhLjIwMTkuc3VtLmxzW1tpXV1bWyJseXJfYm90Il1dCiAgICBjIDwtIHZlY3Rvcihtb2RlID0gImxpc3QiLCBsZW5ndGggPSBsZW5ndGgoZCkpCiAgICBmb3IoaiBpbiBzZXFfYWxvbmcoZCkpIHsKICAgICAgaWYoaiA9PSAxKSB7CiAgICAgICAgY1tbal1dIDwtIHNyYS4yMDAxLm9jLnNwLmF2Z1tbaV1dWzE6ZFtqXSwgImx5cl9zb2MiXQogICAgICB9IGVsc2UgewogICAgICAgIGNbW2pdXSA8LSBzcmEuMjAwMS5vYy5zcC5hdmdbW2ldXVsoZFtqLTFdKzEpOmRbal0sICJseXJfc29jIl0gCiAgICAgIH0KICAgIH0KICAgIHJldHVybih1bmxpc3QobGFwcGx5KGMsIGZ1bmN0aW9uKHgpIHgvc3VtKHgpKSkpCn0pCm5hbWVzKGN3dC4xOS4wMS5hdmcpIDwtIG5hbWVzKHNyYS4yMDAxLm9jLnNwKQoKIyAyMDA5CmN3dC4xOS4wOSA8LSBsYXBwbHkoc2VxX2Fsb25nKHNyYS4yMDA5Lm9jLnNwKSwgZnVuY3Rpb24oaSkgewogIGQgPC0gc3JhLjIwMTkuc3VtLmxzW1tpXV1bWyJseXJfYm90Il1dCiAgYyA8LSB2ZWN0b3IobW9kZSA9ICJsaXN0IiwgbGVuZ3RoID0gbGVuZ3RoKGQpKQogIGZvcihqIGluIHNlcV9hbG9uZyhkKSkgewogICAgaWYoaiA9PSAxKSB7CiAgICAgIGNbW2pdXSA8LSBzcmEuMjAwOS5vYy5zcFtbaV1dWzE6ZFtqXSwgImx5cl9zb2MiXQogICAgfSBlbHNlIHsKICAgICAgY1tbal1dIDwtIHNyYS4yMDA5Lm9jLnNwW1tpXV1bKGRbai0xXSsxKTpkW2pdLCAibHlyX3NvYyJdIAogICAgfQogIH0KICByZXR1cm4odW5saXN0KGxhcHBseShjLCBmdW5jdGlvbih4KSB4L3N1bSh4KSkpKQp9KQpuYW1lcyhjd3QuMTkuMDkpIDwtIG5hbWVzKHNyYS4yMDA5Lm9jLnNwKQoKIyMgY2FsY3VsYXRlIGZtX3d0cwojIyAnMTkgZGVwdGhzCiMjIGJ1bGsKIyAyMDAxCmZtLnd0LjE5LjAxIDwtIGxhcHBseShzZXFfYWxvbmcoY3d0LjE5LjAxKSwgZnVuY3Rpb24oaSkgewogIGxhcHBseShzZXFfYWxvbmcoY3d0LjE5LjAxW1tpXV0pLCBmdW5jdGlvbihqKSB7CiAgICBkZiA8LSBkYXRhLmZyYW1lKGN3dCA9IGN3dC4xOS4wMVtbaV1dW1tqXV0pCiAgICBkZiRmbSA8LSBzcmEuMjAwMS5mbS5zcFtbaV1dW1tqXV1bWyJ2YXIuMWNtIl1dWzE6bGVuZ3RoKGN3dC4xOS4wMVtbaV1dW1tqXV0pXQogICAgIyBsaW5lYXIgZXh0cmFwb2xhdGlvbiBmb3IgZmlsbGluZyAyMC0zMGNtIGZtIGRhdGEKICAgIGZtXzFfMzAgPC0gZGYkZm1bMTozMF0gIyAwLTMwY20gZm0KICAgIGlmKGxlbmd0aCh3aGljaChpcy5uYShmbV8xXzMwKSkpID4gMCkgewogICAgIGl4IDwtIHdoaWNoKGlzLm5hKGZtXzFfMzApKQogICAgIGl4Lm1pbiA8LSBtaW4oaXgpICMgZmlyc3QgaXMubmEoZm0pCiAgICAgbSA8LSBmbV8xXzMwW2l4Lm1pbi0xXS1mbV8xXzMwW2l4Lm1pbi0yXSAjIHNsb3BlIGF0IGxhc3QgdHdvIG1lYXN1cmVtZW50IHBvaW50cwogICAgIGZvcihpIGluIGl4Lm1pbjozMCkgewogICAgICBmbV8xXzMwW2ldIDwtIGZtXzFfMzBbaSAtIDFdICsgbSAKICAgICB9CiAgICAgZGYkZm1bMTozMF0gPC0gZm1fMV8zMCAKICAgIH0KICAgIGRmJGZtX3d0IDwtIGRmJGZtICogZGYkY3d0CiAgcmV0dXJuKGRmKQogIH0pCn0pCm5hbWVzKGZtLnd0LjE5LjAxKSA8LSBuYW1lcyhjd3QuMTkuMDEpCgojICcwMSBpbmMKZm0ud3QuMTkuMDEuaW5jIDwtIGxhcHBseShzZXFfYWxvbmcoY3d0LjE5LjAxLmF2ZyksIGZ1bmN0aW9uKGopIHsKICBsYXBwbHkoc3JhLjIwMDEuaW5jLmZtLnNwW1tqXV0sIGZ1bmN0aW9uKGZtKSB7CiAgICBkZiA8LSBkYXRhLmZyYW1lKGN3dCA9IGN3dC4xOS4wMS5hdmdbW2pdXVsxOjMwXSkKICAgICMgbGluZWFyIGV4dHJhcG9sYXRpb24gZm9yIGZpbGxpbmcgMjAtMzBjbSBmbSBkYXRhCiAgICBpZiAobGVuZ3RoKGZtKSA+PSAzMCkgewogICAgICBmbV8xXzMwIDwtIGZtWzE6MzBdICMgMC0zMGNtIGZtCiAgICB9IGVsc2UgewogICAgICBmbV8xXzMwIDwtIHJlcChOQSwgMzApCiAgICAgIGZtXzFfMzBbMTpsZW5ndGgoZm0pXSA8LSBmbQogICAgICAjIGZpcnN0IGlzLm5hKGZtKQogICAgICBpeC5taW4gPC0gbWluKHdoaWNoKGlzLm5hKGZtXzFfMzApKSkKICAgICAgIyBzbG9wZSBhdCBsYXN0IHR3byBtZWFzdXJlbWVudCBwb2ludHMKICAgICAgbSA8LSBmbV8xXzMwW2l4Lm1pbiAtIDFdIC0gZm1fMV8zMFtpeC5taW4gLSAyXQogICAgICBmb3IoeCBpbiBpeC5taW46MzApIHsKICAgICAgICBmbV8xXzMwW3hdIDwtIGZtXzFfMzBbeCAtIDFdICsgbQogICAgICB9CiAgICB9CiAgICBkZiRmbVsxOjMwXSA8LSBmbV8xXzMwIAogICAgZGYkZm1fd3QgPC0gZGYkZm0gKiBkZiRjd3QKICAgIHJldHVybihkZikKICB9KQp9KQpuYW1lcyhmbS53dC4xOS4wMS5pbmMpIDwtIG5hbWVzKGN3dC4xOS4wMS5hdmcpCgojIDIwMDkKZm0ud3QuMTkuMDkgPC0gbGFwcGx5KHNlcV9hbG9uZyhjd3QuMTkuMDkpLCBmdW5jdGlvbihpKSB7CiAgZGYgPC0gZGF0YS5mcmFtZShjd3QgPSBjd3QuMTkuMDlbW2ldXSkKICBkZiRmbSA8LSBzcmEuMjAwOS5mbS5zcFtbaV1dW1sidmFyLjFjbSJdXVsxOmxlbmd0aChjd3QuMTkuMDlbW2ldXSldCiAgZGYkZm1fd3QgPC0gZGYkZm0gKiBkZiRjd3QKICByZXR1cm4oZGYpCn0pCm5hbWVzKGZtLnd0LjE5LjA5KSA8LSBuYW1lcyhjd3QuMTkuMDkpCgojIyBjYWxjdWxhdGUgd2VpZ2h0ZWQgYXZlcmFnZSBvZiBmbSBmb3IgZWFjaCBpbnRlcnZhbAojIyAnMTkgZGVwdGhzCiMgMjAwMQojIGNhbGN1bGF0ZSB3ZWlnaHRlZCBzcGxpbmUgdmFsdWVzIGZvciBlYWNoIHByb2ZpbGUgcmVwCnNyYS4xOS4wMS5yZXAubHMgPC0gZm0ud3QuMTkuMDEKc3JhLjE5LjAxLnJlcC5scyA8LSBsYXBwbHkoc2VxX2Fsb25nKHNyYS4yMDE5LnN1bS5scyksIGZ1bmN0aW9uKGkpIHsKICBzcmEuMTkuMDEucmVwLmxzW1tpXV0gPC0gbGFwcGx5KHNlcV9hbG9uZyhmbS53dC4xOS4wMVtbaV1dKSwgZnVuY3Rpb24oeCkgewogICAgZCA8LSBzcmEuMjAxOS5zdW0ubHNbW2ldXVtbImx5cl9ib3QiXV0KICAgIGYgPC0gdmVjdG9yKG1vZGUgPSAibGlzdCIsIGxlbmd0aCA9IGxlbmd0aChkKSkKICAgIGZvcihqIGluIHNlcV9hbG9uZyhkKSkgewogICAgICBpZihqID09IDEpIHsKICAgICAgICBmW1tqXV0gPC0gc3VtKGZtLnd0LjE5LjAxW1tpXV1bW3hdXVsxOmRbal0sICJmbV93dCJdKQogICAgICB9IGVsc2UgewogICAgICAgIGZbW2pdXSA8LSBzdW0oZm0ud3QuMTkuMDFbW2ldXVtbeF1dWyhkW2otMV0rMSk6ZFtqXSwgImZtX3d0Il0pCiAgICAgIH0KICAgIH0KICAgIHJldHVybih1bmxpc3QoZikpIAogIH0pfSkKc3JhLjE5LjAxLnJlcC5scyA8LSBsYXBwbHkoc2VxX2Fsb25nKHNyYS4xOS4wMS5yZXAubHMpLCBmdW5jdGlvbihpKSB7CiAgbmFtZXMoc3JhLjE5LjAxLnJlcC5sc1tbaV1dKSA8LSBuYW1lcyhjd3QuMTkuMDFbW2ldXSkKICByZXR1cm4oc3JhLjE5LjAxLnJlcC5sc1tbaV1dKQp9KQpuYW1lcyhzcmEuMTkuMDEucmVwLmxzKSA8LSBuYW1lcyhmbS53dC4xOS4wMSkKc2F2ZShzcmEuMTkuMDEucmVwLmxzLCBmaWxlID0gInNyYS4xOS4wMS5yZXAubHMuUkRhdGEiKQoKIyBhdmVyYWdlIHJlcHMKc3JhLjE5LjAxLmxzIDwtIGxhcHBseShzZXFfYWxvbmcoc3JhLjIwMTkuc3VtLmxzKSwgZnVuY3Rpb24oaSkgewogIGZtIDwtIGxhcHBseShzZXFfYWxvbmcoc3JhLjE5LjAxLnJlcC5sc1tbaV1dW1sxXV0pLCBmdW5jdGlvbih6KSB7CiAgICBkYXRhLmZyYW1lKGZtXzAxX21lYW4gPSBtZWFuKHNhcHBseShzcmEuMTkuMDEucmVwLmxzW1tpXV0sICJbIiwgeiksIG5hLnJtID0gVFJVRSksCiAgICAgICAgICAgICAgIGZtXzAxX3NkID0gc2Qoc2FwcGx5KHNyYS4xOS4wMS5yZXAubHNbW2ldXSwgIlsiLCB6KSwgbmEucm0gPSBUUlVFKSkKICAgIH0pCiAgcmV0dXJuKGJpbmRfcm93cyhmbSkpCn0pCm5hbWVzKHNyYS4xOS4wMS5scykgPC0gbmFtZXMoZm0ud3QuMTkuMDEpCgojIyAnMDEgaW5jCnNyYS4xOS4wMS5pbmMubHMgPC0gbGFwcGx5KGZtLnd0LjE5LjAxLmluYywgZnVuY3Rpb24obHMpIHsKICBsYXBwbHkobHMsIGZ1bmN0aW9uKGRmKSB7CiAgICBkIDwtIGMoMTAsIDIwLCAzMCkKICAgIGYgPC0gdmVjdG9yKG1vZGUgPSAibGlzdCIsIGxlbmd0aCA9IGxlbmd0aChkKSkKICAgIGZvcihqIGluIHNlcV9hbG9uZyhkKSkgewogICAgICBpZihqID09IDEpIHsKICAgICAgICBmW1tqXV0gPC0gc3VtKGRmWzE6ZFtqXSwgImZtX3d0Il0pCiAgICAgIH0gZWxzZSB7CiAgICAgICAgZltbal1dIDwtIHN1bShkZlsoZFtqLTFdKzEpOmRbal0sICJmbV93dCJdKQogICAgICB9CiAgICB9CiAgICByZXR1cm4odW5saXN0KGYpKSAKICB9KX0pCgojIDIwMDkKc3JhLjE5LjA5LmxzIDwtIGxhcHBseShzZXFfYWxvbmcoc3JhLjIwMTkuc3VtLmxzKSwgZnVuY3Rpb24oaSkgewogIGQgPC0gc3JhLjIwMTkuc3VtLmxzW1tpXV1bWyJseXJfYm90Il1dCiAgZiA8LSB2ZWN0b3IobW9kZSA9ICJsaXN0IiwgbGVuZ3RoID0gbGVuZ3RoKGQpKQogIGZvcihqIGluIHNlcV9hbG9uZyhkKSkgewogICAgaWYoaiA9PSAxKSB7CiAgICAgIGZbW2pdXSA8LSBzdW0oZm0ud3QuMTkuMDlbW2ldXVsxOmRbal0sICJmbV93dCJdKQogICAgfSBlbHNlIHsKICAgICAgZltbal1dIDwtIHN1bShmbS53dC4xOS4wOVtbaV1dWyhkW2otMV0rMSk6ZFtqXSwgImZtX3d0Il0pCiAgICB9CiAgfQogIHJldHVybihjYmluZChzcmEuMjAxOS5zdW0ubHNbW2ldXSwgZm1fMDkgPSB1bmxpc3QoZikpKQp9KQpuYW1lcyhzcmEuMTkuMDkubHMpIDwtIG5hbWVzKHNyYS4xOS4wMS5scykKCiMgY29tYmluZQpzcmEuMTkuMDEuMDkubHMgPC0gbGFwcGx5KHNlcV9hbG9uZyhzcmEuMTkuMDEubHMpLCBmdW5jdGlvbihpKSB7CiAgZGF0YS5mcmFtZShzcmEuMTkuMDEubHNbW2ldXSwgc3JhLjE5LjA5LmxzW1tpXV0pCn0pCm5hbWVzKHNyYS4xOS4wMS4wOS5scykgPC0gbmFtZXMoc3JhLjE5LjAxLmxzKQoKIyMgY3JlYXRlIHRpZHkgY29tYmluZWQgJzAxLCAnMDksICcxOSBkYXRhIGZyYW1lCnNyYS4xOS4wMS4wOS5kZiA8LSBiaW5kX3Jvd3Moc3JhLjE5LjAxLjA5LmxzKQpzcmEuMTkuMDEuMDkgPC0gc3JhLjE5LjAxLjA5LmRmWywgbm1zXQpzcmEuMTkuMDEuMDkgPC0gcmJpbmQoZGF0YS5mcmFtZShzcmEuMTkuMDEuMDlbLCBubXNbMTo1XV0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZtID0gc3JhLjE5LjAxLjA5LmRmJGZtXzAxX21lYW4sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZtX3NkID0gc3JhLjE5LjAxLjA5LmRmJGZtXzAxX3NkLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBZZWFyID0gYXMuY2hhcmFjdGVyKDIwMDEpKSwKICAgICAgICAgICAgICAgICAgICAgZGF0YS5mcmFtZShzcmEuMTkuMDEuMDlbLCBubXNbMTo1XV0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZm0gPSBzcmEuMTkuMDEuMDkuZGYkZm1fMDksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZm1fc2QgPSBOQSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBZZWFyID0gYXMuY2hhcmFjdGVyKDIwMDkpKSwKICAgICAgICAgICAgICAgICAgICAgY2JpbmQoc3JhLjE5LjAxLjA5LCBZZWFyID0gYXMuY2hhcmFjdGVyKDIwMTkpKSkKCiMgY2FsYyBkMTRjIGZyb20gZm0Kc3JhLjE5LjAxLjA5JGQxNGMgPC0gY2FsY18xNGMoc3JhLjE5LjAxLjA5JGZtLCBhcy5udW1lcmljKGFzLmNoYXJhY3RlcihzcmEuMTkuMDEuMDkkWWVhcikpKQpzcmEuMTkuMDEuMDkkZDE0Y19zZCA8LSBhYnMoc3JhLjE5LjAxLjA5JGQxNGMgLSBjYWxjXzE0YyhzcmEuMTkuMDEuMDkkZm0gKyBzcmEuMTkuMDEuMDkkZm1fc2QsIGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKHNyYS4xOS4wMS4wOSRZZWFyKSkpKQpzYXZlKHNyYS4xOS4wMS4wOSwgZmlsZSA9ICJzcmEuMTkuMDEuMDkuUkRhdGEiKQpgYGAKCmBgYHtyIGN3dC0xOS0wMS0wXzMwY219CiMjIyMgMC0zMGNtCiMjIyBidWxrCiMjIDIwMTkKIyBTT0Mgd2VpZ2h0cwpjd3QuMTlfMzAgPC0gbGFwcGx5KHNlcV9hbG9uZyhzcmEuMjAxOS5vYy5zcCksIGZ1bmN0aW9uKGkpIHsKICBsYXBwbHkoc3JhLjIwMTkub2Muc3BbW2ldXSwgZnVuY3Rpb24oZGYpIHsKICAgIGQgPC0gMzAKICAgIGMgPC0gZGZbMTpkLCAibHlyX3NvYyJdCiAgICByZXR1cm4odW5saXN0KGxhcHBseShjLCBmdW5jdGlvbih4KSB4L3N1bShjKSkpKQogIH0pCn0pCm5hbWVzKGN3dC4xOV8zMCkgPC0gbmFtZXMoc3JhLjIwMTkub2Muc3ApCiMgRk0gd3RzCmZtLnd0LjE5XzMwIDwtIGxhcHBseShzZXFfYWxvbmcoY3d0LjE5XzMwKSwgZnVuY3Rpb24oaSkgewogIGxhcHBseShzZXFfYWxvbmcoY3d0LjE5XzMwW1tpXV0pLCBmdW5jdGlvbihqKSB7CiAgICBkZiA8LSBkYXRhLmZyYW1lKGN3dCA9IGN3dC4xOV8zMFtbaV1dW1tqXV0pCiAgICBkZiRmbSA8LSBzcmEuMjAxOS5mbS5zcFtbaV1dW1tqXV1bWyJ2YXIuMWNtIl1dWzE6bGVuZ3RoKGN3dC4xOV8zMFtbaV1dW1tqXV0pXQogICAgZGYkZm1fd3QgPC0gZGYkZm0gKiBkZiRjd3QKICByZXR1cm4oZGYpCiAgfSkKfSkgCm5hbWVzKGZtLnd0LjE5XzMwKSA8LSBuYW1lcyhjd3QuMTlfMzApCiMgc3VtbWFyaXplIG92ZXIgMC0zMGNtCnNyYS4xOS5yZXAuMzAubHMgPC0gbGFwcGx5KHNlcV9hbG9uZygxOjkpLCBmdW5jdGlvbihpKSB7CiAgbGFwcGx5KHNlcV9hbG9uZyhmbS53dC4xOV8zMFtbaV1dKSwgZnVuY3Rpb24oeCkgewogICAgZCA8LSAzMAogICAgZiA8LSBzdW0oZm0ud3QuMTlfMzBbW2ldXVtbeF1dWzE6ZCwgImZtX3d0Il0pCiAgICByZXR1cm4odW5saXN0KGYpKSAKICB9KQp9KQpuYW1lcyhzcmEuMTkucmVwLjMwLmxzKSA8LSBuYW1lcyhmbS53dC4xOV8zMCkKc3JhLjE5LmF2Zy4zMC5scyA8LSBsYXBwbHkoc2VxX2Fsb25nKHNyYS4yMDE5LnN1bS5scyksIGZ1bmN0aW9uKGkpIHsKICBmbSA8LSBsYXBwbHkoc2VxX2Fsb25nKHNyYS4xOS5yZXAuMzAubHNbW2ldXVtbMV1dKSwgZnVuY3Rpb24oeikgewogICAgZGF0YS5mcmFtZShmbV8xOV9tZWFuID0gbWVhbihzYXBwbHkoc3JhLjE5LnJlcC4zMC5sc1tbaV1dLCAiWyIsIHopLCBuYS5ybSA9IFRSVUUpLAogICAgICAgICAgICAgICBmbV8xOV9zZCA9IHNkKHNhcHBseShzcmEuMTkucmVwLjMwLmxzW1tpXV0sICJbIiwgeiksIG5hLnJtID0gVFJVRSkpCiAgICB9KQogIHJldHVybihiaW5kX3Jvd3MoZm0pKQp9KQpuYW1lcyhzcmEuMTkuYXZnLjMwLmxzKSA8LSBuYW1lcyhmbS53dC4xOV8zMCkKCiMjIDIwMDEKIyBTT0Mgd2VpZ2h0cwpjd3QuMDFfMzAgPC0gbGFwcGx5KHNyYS4yMDAxLm9jLnNwLCBmdW5jdGlvbihscykgewogIGxhcHBseShscywgZnVuY3Rpb24oZGYpIHsKICAgIGQgPC0gMzAKICAgIGMgPC0gZGZbMTpkLCAibHlyX3NvYyJdCiAgICByZXR1cm4odW5saXN0KGxhcHBseShjLCBmdW5jdGlvbih4KSB4L3N1bShjKSkpKQogIH0pCn0pCm5hbWVzKGN3dC4wMV8zMCkgPC0gbmFtZXMoc3JhLjIwMDEub2Muc3ApCiMgRk0gd3RzCmZtLnd0LjAxXzMwIDwtIGxhcHBseShzZXFfYWxvbmcoY3d0LjAxXzMwKSwgZnVuY3Rpb24oaSkgewogIGxhcHBseShzZXFfYWxvbmcoY3d0LjAxXzMwW1tpXV0pLCBmdW5jdGlvbihqKSB7CiAgICBkZiA8LSBkYXRhLmZyYW1lKGN3dCA9IGN3dC4wMV8zMFtbaV1dW1tqXV0pCiAgICBkZiRmbSA8LSBzcmEuMjAwMS5mbS5zcFtbaV1dW1tqXV1bWyJ2YXIuMWNtIl1dWzE6bGVuZ3RoKGN3dC4wMV8zMFtbaV1dW1tqXV0pXQogICAgIyBsaW5lYXIgZXh0cmFwb2xhdGlvbiBmb3IgZmlsbGluZyAyMC0zMGNtIGZtIGRhdGEKICAgIGZtXzFfMzAgPC0gZGYkZm1bMTozMF0gIyAwLTMwY20gZm0KICAgIGlmKGxlbmd0aCh3aGljaChpcy5uYShmbV8xXzMwKSkpID4gMCkgewogICAgIGl4IDwtIHdoaWNoKGlzLm5hKGZtXzFfMzApKQogICAgIGl4Lm1pbiA8LSBtaW4oaXgpICMgZmlyc3QgaXMubmEoZm0pCiAgICAgbSA8LSBmbV8xXzMwW2l4Lm1pbi0xXS1mbV8xXzMwW2l4Lm1pbi0yXSAjIHNsb3BlIGF0IGxhc3QgdHdvIG1lYXN1cmVtZW50IHBvaW50cwogICAgIGZvcihpIGluIGl4Lm1pbjozMCkgewogICAgICBmbV8xXzMwW2ldIDwtIGZtXzFfMzBbaSAtIDFdICsgbSAKICAgICB9CiAgICAgZGYkZm1bMTozMF0gPC0gZm1fMV8zMCAKICAgIH0KICAgIGRmJGZtX3d0IDwtIGRmJGZtICogZGYkY3d0CiAgcmV0dXJuKGRmKQogIH0pCn0pIApuYW1lcyhmbS53dC4wMV8zMCkgPC0gbmFtZXMoY3d0LjAxXzMwKQojIHN1bW1hcml6ZSBvdmVyIDAtMzBjbQpzcmEuMDEucmVwLjMwLmxzIDwtIGxhcHBseShzZXFfYWxvbmcoMTo5KSwgZnVuY3Rpb24oaSkgewogIGxhcHBseShzZXFfYWxvbmcoZm0ud3QuMDFfMzBbW2ldXSksIGZ1bmN0aW9uKHgpIHsKICAgIGQgPC0gMzAKICAgIGYgPC0gc3VtKGZtLnd0LjAxXzMwW1tpXV1bW3hdXVsxOmQsICJmbV93dCJdKQogICAgcmV0dXJuKHVubGlzdChmKSkgCiAgfSkKfSkKbmFtZXMoc3JhLjAxLnJlcC4zMC5scykgPC0gbmFtZXMoZm0ud3QuMDFfMzApCnNyYS4wMS5hdmcuMzAubHMgPC0gbGFwcGx5KHNlcV9hbG9uZygxOjkpLCBmdW5jdGlvbihpKSB7CiAgZm0gPC0gbGFwcGx5KHNlcV9hbG9uZyhzcmEuMDEucmVwLjMwLmxzW1tpXV1bWzFdXSksIGZ1bmN0aW9uKHopIHsKICAgIGRhdGEuZnJhbWUoZm1fMDFfbWVhbiA9IG1lYW4oc2FwcGx5KHNyYS4wMS5yZXAuMzAubHNbW2ldXSwgIlsiLCB6KSwgbmEucm0gPSBUUlVFKSwKICAgICAgICAgICAgICAgZm1fMDFfc2QgPSBzZChzYXBwbHkoc3JhLjAxLnJlcC4zMC5sc1tbaV1dLCAiWyIsIHopLCBuYS5ybSA9IFRSVUUpKQogICAgfSkKICByZXR1cm4oYmluZF9yb3dzKGZtKSkKfSkKbmFtZXMoc3JhLjAxLmF2Zy4zMC5scykgPC0gbmFtZXMoZm0ud3QuMDFfMzApCgojIyMgaW5jCiMjIDIwMTkKIyBTT0Mgd2VpZ2h0cyAoc2l0ZSBhdmVyYWdlKQpjd3QuMTlfMzAuYXZnIDwtIGxhcHBseShjd3QuMTlfMzAsIGZ1bmN0aW9uKGxzKSB7CiAgYXBwbHkoYmluZF9yb3dzKGxzKSwgMSwgbWVhbikKfSkKIyBGbHV4IHdlaWdodHMgKHNpdGUgYXZlcmFnZSkKCmN3dC4xOV8zMC5hdmcgPC0gbGFwcGx5KGN3dC4xOV8zMCwgZnVuY3Rpb24obHMpIHsKICBhcHBseShiaW5kX3Jvd3MobHMpLCAxLCBtZWFuKQp9KQojIEZNIHdlaWdodHMKZm0ud3QuMTkuMzAuaW5jIDwtIGxhcHBseShzZXFfYWxvbmcoY3d0LjE5XzMwLmF2ZyksIGZ1bmN0aW9uKGopIHsKICBsYXBwbHkoc3JhLjIwMTkuaW5jLmZtLnNwW1tqXV0sIGZ1bmN0aW9uKGZtKSB7CiAgICBkZiA8LSBkYXRhLmZyYW1lKGN3dCA9IGN3dC4xOV8zMC5hdmdbW2pdXSkKICAgIGRmJGZtIDwtIGZtCiAgICBkZiRmbV93dCA8LSBkZiRmbSAqIGRmJGN3dAogIHJldHVybihkZikKICB9KQp9KSAKbmFtZXMoZm0ud3QuMTkuMzAuaW5jKSA8LSBuYW1lcyhjd3QuMTlfMzAuYXZnKQojIHN1bW1hcml6ZSBvdmVyIDAtMzBjbQpzcmEuMTkuMzAuaW5jLmxzIDwtIGxhcHBseShmbS53dC4xOS4zMC5pbmMsIGZ1bmN0aW9uKGxzKSB7CiAgbHMgPC0gbGFwcGx5KGxzLCBmdW5jdGlvbihkZikgc3VtKGRmJGZtX3d0KSkKICBuYW1lcyhscykgPC0gYygiZm1fMTlfbWVhbiIsICJmbV8xOV9taW4iLCAiZm1fMTlfbWF4IikKICByZXR1cm4oZGF0YS5mcmFtZShiaW5kX3Jvd3MobHMpKSkKfSkKbmFtZXMoc3JhLjE5LjMwLmluYy5scykgPC0gbmFtZXMoY3d0LjE5XzMwLmF2ZykKCiMjIDIwMDEKIyBTT0Mgd2VpZ2h0cyAoc2l0ZSBhdmVyYWdlKQpjd3QuMDFfMzAuYXZnIDwtIGxhcHBseShjd3QuMDFfMzAsIGZ1bmN0aW9uKGxzKSB7CiAgYXBwbHkoYmluZF9yb3dzKGxzKSwgMSwgbWVhbikKfSkKIyBGTSB3ZWlnaHRzCmZtLnd0LjAxLjMwLmluYyA8LSBsYXBwbHkoc2VxX2Fsb25nKGN3dC4wMV8zMC5hdmcpLCBmdW5jdGlvbihqKSB7CiAgbGFwcGx5KHNyYS4yMDAxLmluYy5mbS5zcFtbal1dLCBmdW5jdGlvbihmbSkgewogICAgZGYgPC0gZGF0YS5mcmFtZShjd3QgPSBjd3QuMDFfMzAuYXZnW1tqXV0pCiAgICBkZiRmbSA8LSBmbVsxOmxlbmd0aChjd3QuMDFfMzAuYXZnW1tqXV0pXQogICAgIyBsaW5lYXIgZXh0cmFwb2xhdGlvbiBmb3IgZmlsbGluZyAyMC0zMGNtIGZtIGRhdGEKICAgIGZtXzFfMzAgPC0gZGYkZm1bMTozMF0gIyAwLTMwY20gZm0KICAgIGlmKGxlbmd0aCh3aGljaChpcy5uYShmbV8xXzMwKSkpID4gMCkgewogICAgIGl4IDwtIHdoaWNoKGlzLm5hKGZtXzFfMzApKQogICAgIGl4Lm1pbiA8LSBtaW4oaXgpICMgZmlyc3QgaXMubmEoZm0pCiAgICAgbSA8LSBmbV8xXzMwW2l4Lm1pbi0xXS1mbV8xXzMwW2l4Lm1pbi0yXSAjIHNsb3BlIGF0IGxhc3QgdHdvIG1lYXN1cmVtZW50IHBvaW50cwogICAgIGZvcihpIGluIGl4Lm1pbjozMCkgewogICAgICBmbV8xXzMwW2ldIDwtIGZtXzFfMzBbaSAtIDFdICsgbSAKICAgICB9CiAgICAgZGYkZm1bMTozMF0gPC0gZm1fMV8zMCAKICAgIH0KICAgIGRmJGZtX3d0IDwtIGRmJGZtICogZGYkY3d0CiAgcmV0dXJuKGRmKQogIH0pCn0pIApuYW1lcyhmbS53dC4wMS4zMC5pbmMpIDwtIG5hbWVzKGN3dC4wMV8zMC5hdmcpCiMgc3VtbWFyaXplIG92ZXIgMC0zMGNtCnNyYS4wMS4zMC5pbmMubHMgPC0gbGFwcGx5KGZtLnd0LjAxLjMwLmluYywgZnVuY3Rpb24obHMpIHsKICBscyA8LSBsYXBwbHkobHMsIGZ1bmN0aW9uKGRmKSBzdW0oZGYkZm1fd3QpKQogIG5hbWVzKGxzKSA8LSBjKCJmbV8wMV9tZWFuIiwgImZtXzAxX21pbiIsICJmbV8wMV9tYXgiKQogIHJldHVybihkYXRhLmZyYW1lKGJpbmRfcm93cyhscykpKQp9KQpuYW1lcyhzcmEuMDEuMzAuaW5jLmxzKSA8LSBuYW1lcyhjd3QuMDFfMzAuYXZnKQoKIyMgZGYgZm9yIGxpbmVhciBtb2RlbGluZwojIGJ1bGsKc3JhLmJsay5yZXAuMzAubHMgPC0gbGFwcGx5KHNlcV9hbG9uZyhzcmEuMDEucmVwLjMwLmxzKSwgZnVuY3Rpb24oaSkgewogIGJsay4wMSA8LSBkYXRhLmZyYW1lKGZtX2JsayA9IGRvLmNhbGwocmJpbmQsIHNyYS4wMS5yZXAuMzAubHNbW2ldXSksCiAgICAgICAgICAgICAgICAgICAgICAgeWVhciA9IDIwMDEpCiAgYmxrLjE5IDwtIGRhdGEuZnJhbWUoZm1fYmxrID0gZG8uY2FsbChyYmluZCwgc3JhLjE5LnJlcC4zMC5sc1tbaV1dKSwKICAgICAgICAgICAgICAgICAgICAgICB5ZWFyID0gMjAxOSkKICByYmluZChibGsuMDEsIGJsay4xOSkgJT4lCiAgICBtdXRhdGUoZDE0Y19ibGsgPSBjYWxjXzE0YyhmbV9ibGssIHllYXIpKQp9KQpuYW1lcyhzcmEuYmxrLnJlcC4zMC5scykgPC0gbmFtZXMoc3JhLjAxLjMwLmluYy5scykKc3JhLmJsay5yZXAuMzAuZGYgPC0gYmluZF9yb3dzKHNyYS5ibGsucmVwLjMwLmxzLCAuaWQgPSAiUE1lY28iKQojIGluYwppbmMuMzAuYmluZC5meCA8LSBmdW5jdGlvbihscywgeWVhcl94eCkgewogIHJiaW5kKAogICAgYmluZF9yb3dzKGxhcHBseShscywgIlsiLCAyKSwgLmlkID0gIlBNZWNvIikgJT4lCiAgICAgIHJlbmFtZShmbV9pbmMgPSBwYXN0ZTAoImZtXyIsIHllYXJfeHgsICJfbWluIikpLAogICAgYmluZF9yb3dzKGxhcHBseShscywgIlsiLCAzKSwgLmlkID0gIlBNZWNvIikgJT4lCiAgICAgIHJlbmFtZShmbV9pbmMgPSBwYXN0ZTAoImZtXyIsIHllYXJfeHgsICJfbWF4IikpKSAlPiUKICAgIG11dGF0ZSh5ZWFyID0gYXMubnVtZXJpYyhwYXN0ZTAoIjIwIiwgeWVhcl94eCkpKSAlPiUKICAgIG11dGF0ZShkMTRjX2luYyA9IGNhbGNfMTRjKGZtX2luYywgeWVhcikpCn0Kc3JhLmluYy5yZXAuMzAuZGYgPC0gcmJpbmQoaW5jLjMwLmJpbmQuZngoc3JhLjAxLjMwLmluYy5scywgIjAxIiksIAogICAgICAgICAgICAgICAgICAgICAgICAgICBpbmMuMzAuYmluZC5meChzcmEuMTkuMzAuaW5jLmxzLCAiMTkiKSkKIyBjb21iaW5lCnNyYS5ibGsuaW5jLnJlcC4zMC5kZiA8LSBtZXJnZShzcmEuYmxrLnJlcC4zMC5kZiwgc3JhLmluYy5yZXAuMzAuZGYsIGJ5ID0gYygieWVhciIsICJQTWVjbyIpKQpzYXZlKHNyYS5ibGsuaW5jLnJlcC4zMC5kZiwgZmlsZSA9ICJzcmEuYmxrLmluYy5yZXAuMzAuZGYuUkRhdGEiKQoKIyMgQ29tYmluZSBtZWFuIGRhdGEgaW50byBhIHNpbmdsZSBkYXRhIGZyYW1lCiMgZnVuY3Rpb25zIGZvciBjb252ZXJ0aW5nIGZtIHRvIGQxNGMgYW5kIGNhbGN1bGF0aW5nIHNkCmJsay4xNGMuc2QuZnggPC0gZnVuY3Rpb24oZGYsIHllYXJfeHgpIHsKICBkYXRlIDwtIGFzLm51bWVyaWMocGFzdGUwKDIwLCB5ZWFyX3h4KSkKICBkZiRmbV91IDwtIGRmW1twYXN0ZTAoImZtXyIsIHllYXJfeHgsICJfbWVhbiIpXV0gKyBkZltbcGFzdGUwKCJmbV8iLCB5ZWFyX3h4LCAiX3NkIildXQogIGRmJGQxNGNfdSA8LSBjYWxjXzE0YyhkZiRmbV91LCBkYXRlKQogIGRmW1twYXN0ZTAoImQxNGNfIiwgIm1lYW4iKV1dIDwtIGNhbGNfMTRjKGRmW1twYXN0ZTAoImZtXyIsIHllYXJfeHgsICJfbWVhbiIpXV0sIGRhdGUpCiAgZGZbW3Bhc3RlMCgiZDE0Y18iLCAic2QiKV1dIDwtIGRmW1twYXN0ZTAoImQxNGNfIiwgIm1lYW4iKV1dIC0gZGYkZDE0Y191CiAgZGYkeWVhciA8LSBhcy5udW1lcmljKHBhc3RlMCgyMCwgeWVhcl94eCkpCiAgcmV0dXJuKGRmICU+JSBzZWxlY3QoYyhzdGFydHNfd2l0aCgiZDE0YyIpLCB5ZWFyKSkgJT4lIHNlbGVjdCgtZDE0Y191KSkKfQppbmMuMTRjLnNkLmZ4IDwtIGZ1bmN0aW9uKGRmLCB5ZWFyX3h4KSB7CiAgbmFtZXMoZGYpIDwtIGdzdWIocGFzdGUwKCJmbV8iLCB5ZWFyX3h4KSwgImQxNGMiLCBuYW1lcyhkZikpCiAgZGZfMTRjIDwtIGNhbGNfMTRjKGRmLCBhcy5udW1lcmljKHBhc3RlMCgyMCwgeWVhcl94eCkpKQogIGRmXzE0Y1tbcGFzdGUwKCJkMTRjXyIsICJzZCIpXV0gPC0gc2QoZGZfMTRjWyAsIDI6M10pCiAgZGZfMTRjJHllYXIgPC0gYXMubnVtZXJpYyhwYXN0ZTAoMjAsIHllYXJfeHgpKQogIHJldHVybihkZl8xNGNbICwgYygxLCA0OjUpXSkKfQojIHJ1biBmdW5jdGlvbnMgYW5kIGNvbWJpbmUgbGlzdHMgCiMgMC0zMGNtIGRhdGEgZnJvbSAnMDEgYW5kICcxOQpzcmEuMzAuYmxrLmluYy5scyA8LSBsYXBwbHkoCiAgbGlzdChsYXBwbHkoc3JhLjAxLjMwLmluYy5scywgaW5jLjE0Yy5zZC5meCwgeWVhcl94eCA9ICIwMSIpLCAKICAgICAgIGxhcHBseShzcmEuMTkuMzAuaW5jLmxzLCBpbmMuMTRjLnNkLmZ4LCB5ZWFyX3h4ID0gIjE5IiksCiAgICAgICBsYXBwbHkoc3JhLjAxLmF2Zy4zMC5scywgYmxrLjE0Yy5zZC5meCwgeWVhcl94eCA9ICIwMSIpLAogICAgICAgbGFwcGx5KHNyYS4xOS5hdmcuMzAubHMsIGJsay4xNGMuc2QuZngsIHllYXJfeHggPSAiMTkiKSksCiAgYmluZF9yb3dzLCAuaWQgPSAiUE1lY28iKQojIHJlZHVjZSBsaXN0IHRvIGRhdGEgZnJhbWUsIGNhbGN1bGF0ZSBkaWZmZXJlbmNlIG9mIG1lYW5zIGFuZCBzZApzcmEuMzAuYmxrLmluYy5kZiA8LSByYmluZChtZXJnZShzcmEuMzAuYmxrLmluYy5sc1tbMV1dLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzcmEuMzAuYmxrLmluYy5sc1tbM11dLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBieSA9IGMoIlBNZWNvIiwgInllYXIiKSwgc3VmZml4ZXMgPSBjKCJfaW5jIiwgIl9ibGsiKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgIG1lcmdlKHNyYS4zMC5ibGsuaW5jLmxzW1syXV0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNyYS4zMC5ibGsuaW5jLmxzW1s0XV0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJ5ID0gYygiUE1lY28iLCAieWVhciIpLCBzdWZmaXhlcyA9IGMoIl9pbmMiLCAiX2JsayIpKSkgJT4lCiAgbXV0YXRlKGJsay5pbmMgPSBkMTRjX21lYW5fYmxrIC0gZDE0Y19tZWFuX2luYywKICAgICAgICAgYmxrLmluYy5zZCA9IHNxcnQoZDE0Y19zZF9ibGteMi8zICsgZDE0Y19zZF9pbmNeMi8yKSkKYGBgCgpgYGB7ciBwbG90LTAxLTA5LTE5LTE0Yy1wcm9maWxlc30KZmlnLm4gPC0gZmlnLm4gKyAxCnNyYS4wMS4wOS4xOSAlPiUKICBtdXRhdGUoUE1lY29feWVhciA9IHBhc3RlMChQTWVjbywgWWVhciksCiAgICAgICAgIGVjbyA9IGZhY3RvcihpZmVsc2UoRUNPID09ICJwcCIsICJ3YXJtIiwKICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShFQ08gPT0gIndmIiwgImNvb2wiLCAiY29sZCIpKSwKICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoIndhcm0iLCAiY29vbCIsICJjb2xkIikpLAogICAgICAgICBkMTRjX3UgPSBkMTRjICsgZDE0Y19zZCwKICAgICAgICAgZDE0Y19sID0gZDE0YyAtIGQxNGNfc2QsCiAgICAgICAgIHBtID0gaWZlbHNlKFBNID09ICJBTiIsICJhbmRlc2l0ZSIsCiAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShQTSA9PSAiQlMiLCAiYmFzYWx0IiwgImdyYW5pdGUiKSkpICU+JQogICMgZmlsdGVyKFllYXIgIT0gIjIwMDkiKSAlPiUKICBnZ3Bsb3QoLiwgYWVzKGQxNGMsIGx5cl9ib3QsIGNvbG9yID0gcG0sIHNoYXBlID0gZWNvLCBsaW5ldHlwZSA9IFllYXIsIGdyb3VwID0gUE1lY29feWVhcikpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCkgKwogIGdlb21fcG9pbnQoYWVzKGFscGhhID0gWWVhciksIHNpemUgPSAzKSArCiAgZ2VvbV9wYXRoKGFlcyhsaW5ldHlwZSA9IFllYXIpKSArCiAgZ2VvbV9lcnJvcmJhcmgoCiAgICBhZXMoeG1pbiA9IGQxNGNfbCwgCiAgICAgICAgeG1heCA9IGQxNGNfdSwKICAgICAgICBjb2xvciA9IHBtKSwgCiAgICBoZWlnaHQgPSAxLjUpICsKICBzY2FsZV95X3JldmVyc2UoKSArCiAgc2NhbGVfeF9jb250aW51b3VzKCkgKyAgICAKICBzY2FsZV9jb2xvcl9tYW51YWwobmFtZSA9ICJQYXJlbnQgbWF0ZXJpYWwiLAogICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSBjKCJhbmRlc2l0ZSIgPSAiYmx1ZSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJiYXNhbHQiID0gInJlZCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJncmFuaXRlIiA9ICJkYXJrZ3JheSIpKSArCiAgc2NhbGVfc2hhcGVfbWFudWFsKG5hbWUgPSAiRWNvc3lzdGVtIiwKICAgICAgICAgICAgICAgICAgICAgdmFsdWVzID0gYygid2FybSIgPSAxNSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImNvb2wiID0gMTYsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJjb2xkIiA9IDE3KSkgKwogIHNjYWxlX2FscGhhX21hbnVhbCh2YWx1ZXMgPSBjKCIyMDAxIiA9IDEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjIwMDkiID0gMC42LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIyMDE5IiA9IDAuMykpICsKICBzY2FsZV9saW5ldHlwZV9tYW51YWwodmFsdWVzID0gYygiMjAwMSIgPSAic29saWQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiMjAwOSIgPSAiZGFzaGVkIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjIwMTkiID0gImRvdHRlZCIpKSArCiAgZmFjZXRfZ3JpZChyb3dzID0gdmFycyhlY28pLCBjb2xzID0gdmFycyhwbSkpICsKICB4bGFiKGV4cHJlc3Npb24oRGVsdGEqJydeMTQqJ0MgKOKAsCknKSkgKwogIHlsYWIoIkRlcHRoIChjbSkiKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUocGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSkKYGBgCj4qKkZpZy4gYHIge2ZpZy5ufWAuIFRpbWUgc2VyaWVzIG9mIGJ1bGsgc29pbCAkXERlbHRhJF4xNF5DIGJ5IDIwMDEgZGVwdGhzICgyMDAxLCAyMDA5LCAyMDE5IHNhbXBsZXMpKioKCj4qQ2FwdGlvbjoqIFBvaW50cyBmb3IgMjAwMSBzYW1wbGVzIHNob3cgdGhlIG1lYW4gJFxEZWx0YSReMTReQyB2YWx1ZXMgYXQgdGhlIG1lYXN1cmVkIGRlcHRocy4gUG9pbnRzIGZvciAyMDA5IGFuZCAyMDE5IHNhbXBsZXMgYXJlIHNwbGluZS1maXR0ZWQgZXN0aW1hdGVzIG9mICRcRGVsdGEkXjE0XkMgcHJlZGljdGVkIGZvciB0aGUgc2FtZSBkZXB0aCBpbnRlcnZhbHMgYXMgbWVhc3VyZWQgaW4gMjAwMS4gRXJyb3IgYmFycyBzaG93IMKxIDEgc3RhbmRhcmQgZGV2aWF0aW9uIG9mIHRoZSBtZWFuIG9mIHRocmVlIHJlcGxpY2F0ZSBwcm9maWxlcyBmb3IgMjAwMSBhbmQgMjAxOSBzYW1wbGVzIChvbmx5IGEgc2luZ2xlIHByb2ZpbGUgd2FzIGFuYWx5emVkIGluIDIwMDkpLiAKCmBgYHtyIHBsb3QtMTktMDEtMDktMTRjLXByb2ZpbGVzfQpmaWcubiA8LSBmaWcubiArIDEKc3JhLjE5LjAxLjA5ICU+JQogIG11dGF0ZShQTWVjb195ZWFyID0gcGFzdGUwKFBNZWNvLCBZZWFyKSwKICAgICAgICAgZWNvID0gZmFjdG9yKGlmZWxzZShFQ08gPT0gInBwIiwgIndhcm0iLAogICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKEVDTyA9PSAid2YiLCAiY29vbCIsICJjb2xkIikpLAogICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gYygid2FybSIsICJjb29sIiwgImNvbGQiKSksCiAgICAgICAgIGQxNGNfdSA9IGQxNGMgKyBkMTRjX3NkLAogICAgICAgICBkMTRjX2wgPSBkMTRjIC0gZDE0Y19zZCwKICAgICAgICAgcG0gPSBpZmVsc2UoUE0gPT0gIkFOIiwgImFuZGVzaXRlIiwKICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKFBNID09ICJCUyIsICJiYXNhbHQiLCAiZ3Jhbml0ZSIpKSkgJT4lCiAgZ2dwbG90KC4sIGFlcyhkMTRjLCBseXJfYm90LCBjb2xvciA9IHBtLCBzaGFwZSA9IGVjbywgbGluZXR5cGUgPSBZZWFyLCBncm91cCA9IFBNZWNvX3llYXIpKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMCkgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDApICsKICBnZW9tX3BvaW50KGFlcyhhbHBoYSA9IFllYXIpLCBzaXplID0gMykgKwogIGdlb21fcGF0aChhZXMobGluZXR5cGUgPSBZZWFyKSkgKwogIGdlb21fZXJyb3JiYXJoKAogICAgYWVzKHhtaW4gPSBkMTRjX2wsIAogICAgICAgIHhtYXggPSBkMTRjX3UsCiAgICAgICAgY29sb3IgPSBwbSksIAogICAgaGVpZ2h0ID0gMS41KSArCiAgIyBzY2FsZV95X3JldmVyc2UobGltaXRzID0gYygzMCwgMCkpICsKICBzY2FsZV95X3JldmVyc2UoKSArCiAgc2NhbGVfeF9jb250aW51b3VzKCkgKyAgICAKICBzY2FsZV9jb2xvcl9tYW51YWwobmFtZSA9ICJQYXJlbnQgbWF0ZXJpYWwiLAogICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSBjKCJhbmRlc2l0ZSIgPSAiYmx1ZSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJiYXNhbHQiID0gInJlZCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJncmFuaXRlIiA9ICJkYXJrZ3JheSIpKSArCiAgc2NhbGVfc2hhcGVfbWFudWFsKG5hbWUgPSAiRWNvc3lzdGVtIiwKICAgICAgICAgICAgICAgICAgICAgdmFsdWVzID0gYygid2FybSIgPSAxNSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImNvb2wiID0gMTYsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJjb2xkIiA9IDE3KSkgKwogIHNjYWxlX2FscGhhX21hbnVhbCh2YWx1ZXMgPSBjKCIyMDAxIiA9IDEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjIwMDkiID0gMC42LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIyMDE5IiA9IDAuMykpICsKICBzY2FsZV9saW5ldHlwZV9tYW51YWwodmFsdWVzID0gYygiMjAwMSIgPSAic29saWQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIyMDA5IiA9ICJkYXNoZWQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIyMDE5IiA9ICJkb3R0ZWQiKSkgKwogIGZhY2V0X2dyaWQocm93cyA9IHZhcnMoZWNvKSwgY29scyA9IHZhcnMocG0pKSArCiAgeGxhYihleHByZXNzaW9uKERlbHRhKicnXjE0KidDICjigLApJykpICsKICB5bGFiKCJEZXB0aCAoY20pIikgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCkpCmBgYAo+KipGaWcuIGByIHtmaWcubn1gLiBUaW1lIHNlcmllcyBvZiBidWxrIHNvaWwgJFxEZWx0YSReMTReQyBieSBkZXB0aCAoc3BsaW5lZCB0byAyMDE5IGRlcHRocykqKgoKPipDYXB0aW9uOiogUG9pbnRzIGZvciAyMDE5IHNhbXBsZXMgc2hvdyB0aGUgbWVhbiAkXERlbHRhJF4xNF5DIHZhbHVlcyBhdCB0aGUgbWVhc3VyZWQgZGVwdGhzLiBQb2ludHMgZm9yIDIwMDEgYW5kIDIwMDkgc2FtcGxlcyBhcmUgc3BsaW5lLWZpdHRlZCBlc3RpbWF0ZXMgb2YgJFxEZWx0YSReMTReQyBwcmVkaWN0ZWQgZm9yIHRoZSBzYW1lIGRlcHRoIGludGVydmFscyBhcyBtZWFzdXJlZCBpbiAyMDE5LiBFcnJvciBiYXJzIHNob3cgwrEgMSBzdGFuZGFyZCBkZXZpYXRpb24gb2YgdGhlIG1lYW4gb2YgdGhyZWUgcmVwbGljYXRlIHByb2ZpbGVzIGZvciAyMDAxIGFuZCAyMDE5IHNhbXBsZXMgKG9ubHkgYSBzaW5nbGUgcHJvZmlsZSB3YXMgYW5hbHl6ZWQgaW4gMjAwOSkuIAo+Kk5COiBPbmx5IHR3byBkZXB0aCBpbnRlcnZhbHMgd2VyZSBtZWFzdXJlZCBhdCB0aGUgY29vbCBhbmQgY29sZCBhbmRlc2l0ZSBzaXRlcyAobWF4IGRlcHRoIG9mIDI3IGFuZCAyOCBjbSwgcmVzcGVjdGl2ZWx5KSwgc28gbGluZWFyIGV4dHJhcG9sYXRpb24gKHVzaW5nIHRoZSBzbG9wZSBvZiB0aGUgbGFzdCAxY20gc3BsaW5lLWZpdHRlZCBkZXB0aCBpbmNyZW1lbnQpIHdhcyB1c2VkIHRvIGV4dGVuZCB0aGUgcHJvZmlsZXMgdG8gMzAgY20uKgoKYGBge3IgcGxvdC1ieS1kZXB0aC0xNEMtdGltZXNlcmllc30KIyBwbG90IGluZGl2aWR1YWwgZGVwdGhzCmZpZy5uIDwtIGZpZy5uICsgMQoKIyBBdG0KYXRtLjE0YyA8LSBkYXRhLmZyYW1lKHllYXIgPSBEYXRtW0RhdG0kRGF0ZSA+IDIwMDAsICJEYXRlIl0sCiAgICAgICAgICAgICAgICAgICAgICBkMTRjID0gRGF0bVtEYXRtJERhdGUgPiAyMDAwLCAiTkhjMTQiXSkKc2F2ZShhdG0uMTRjLCBmaWxlID0gImF0bS4xNGMuUkRhdGEiKQoKIyBidWxrIDE0QyBvdmVyIHRpbWUgZm9yIDAtMTAsIDEwLTIwLCAyMC0zMCB3LyBhdG0Kc3JhLjE5LjAxLjA5ICU+JQogIGZpbHRlcihseXJfYm90IDwgMzEpICU+JQogIG11dGF0ZShQTWVjb19kZXB0aCA9IHBhc3RlMChQTWVjbywgbHlyX2JvdCksCiAgICAgICAgIGRlcHRoID0gZmFjdG9yKGx5cl9ib3QpLAogICAgICAgICBlY28gPSBmYWN0b3IoaWZlbHNlKEVDTyA9PSAicHAiLCAid2FybSIsCiAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoRUNPID09ICJ3ZiIsICJjb29sIiwgImNvbGQiKSksCiAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSBjKCJ3YXJtIiwgImNvb2wiLCAiY29sZCIpKSwKICAgICAgICAgZDE0Y191ID0gZDE0YyArIGQxNGNfc2QsCiAgICAgICAgIGQxNGNfbCA9IGQxNGMgLSBkMTRjX3NkLAogICAgICAgICBwbSA9IGlmZWxzZShQTSA9PSAiQU4iLCAiYW5kZXNpdGUiLAogICAgICAgICAgICAgICAgICAgICBpZmVsc2UoUE0gPT0gIkJTIiwgImJhc2FsdCIsICJncmFuaXRlIikpLAogICAgICAgICB5ZWFyID0gYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoWWVhcikpKSAlPiUKICBnZ3Bsb3QoLiwgYWVzKHllYXIsIGQxNGMpKSArCiAgZ2VvbV9wYXRoKGRhdGEgPSBhdG0uMTRjKSArCiAgZ2VvbV9wb2ludChhZXMoY29sb3IgPSBwbSwgc2hhcGUgPSBlY28pLCBzaXplID0gMykgKwogIGdlb21fcGF0aChhZXMoY29sb3IgPSBwbSwgZ3JvdXAgPSBQTWVjb19kZXB0aCwgbGluZXR5cGUgPSBkZXB0aCksIGFscGhhID0gMC4zKSArCiAgZ2VvbV9lcnJvcmJhcigKICAgIGFlcyh5bWluID0gZDE0Y19sLCAKICAgICAgICB5bWF4ID0gZDE0Y191LAogICAgICAgIGNvbG9yID0gcG0pLCAKICAgIHdpZHRoID0gLjUpICsKICBzY2FsZV9jb2xvcl9tYW51YWwobmFtZSA9ICJQYXJlbnQgbWF0ZXJpYWwiLAogICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSBjKCJhbmRlc2l0ZSIgPSAiYmx1ZSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJiYXNhbHQiID0gInJlZCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJncmFuaXRlIiA9ICJkYXJrZ3JheSIpKSArCiAgc2NhbGVfc2hhcGVfbWFudWFsKG5hbWUgPSAiRWNvc3lzdGVtIiwKICAgICAgICAgICAgICAgICAgICAgdmFsdWVzID0gYygid2FybSIgPSAxNSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImNvb2wiID0gMTYsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJjb2xkIiA9IDE3KSkgKwogIHNjYWxlX2xpbmV0eXBlX21hbnVhbChuYW1lID0gIkRlcHRoIChjbSkiLAogICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCIxMCIgPSAiMC0xMCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjIwIiA9ICIxMC0yMCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjMwIiA9ICIyMC0zMCIpLAogICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSBjKCIxMCIgPSAxLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIyMCIgPSAyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIzMCIgPSAzKSkgKwogIGZhY2V0X2dyaWQocm93cyA9IHZhcnMoZWNvKSwgY29scyA9IHZhcnMocG0pKSArCiAgeWxhYihleHByZXNzaW9uKERlbHRhKicnXjE0KidDICjigLApJykpICsKICB4bGFiKCJZZWFyIikgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKHBhbmVsLmdyaWQgPSBlbGVtZW50X2JsYW5rKCkpCgojIyMgaW5jdWJhdGlvbgojIyAyMDE5CnNyYS4yMDE5LmluYy5kZiA8LSBiaW5kX3Jvd3MobGFwcGx5KHNyYS4yMDE5LmluYy5scywgZnVuY3Rpb24oZGYpIHsKICBkYXRhLmZyYW1lKGRmICU+JQogICAgICAgICAgICAgICBncm91cF9ieShZZWFyLCBQTSwgRUNPLCBseXJfYm90LCBQTWVjbykgJT4lCiAgICAgICAgICAgICAgIHN1bW1hcml6ZSgKICAgICAgICAgICAgICAgICBhY3Jvc3MoLmNvbHMgPSBkMTRjLCAKICAgICAgICAgICAgICAgICAgICAgICAgLmZucyA9IGxpc3QobWVhbiA9IG1lYW4sIG1pbiA9IG1pbiwgbWF4ID0gbWF4KSkpICU+JQogICAgICAgICAgICAgICByZW5hbWUoeWVhciA9IFllYXIsIGQxNGMgPSBkMTRjX21lYW4pKQp9KSkKc2F2ZShzcmEuMjAxOS5pbmMuZGYsIGZpbGUgPSAic3JhLjIwMTkuaW5jLmRmLlJEYXRhIikKIyMgMjAwMQpzcmEuMTkuMDEuaW5jLmRmIDwtIGJpbmRfcm93cyhsYXBwbHkoc2VxX2Fsb25nKHNyYS4xOS4wMS5pbmMubHMpLCBmdW5jdGlvbihpKSB7CiAgUE1lY28gPC0gbmFtZXMoc3JhLjE5LjAxLmluYy5scylbaV0KICBkMTRjLmxzIDwtIGxhcHBseShzcmEuMTkuMDEuaW5jLmxzW1tpXV0sIGNhbGNfMTRjLCBvYnNfZGF0ZV95ID0gMjAwMSkKICBkZiA8LSBkYXRhLmZyYW1lKGQxNGMgPSBkMTRjLmxzW1sxXV0sCiAgICAgICAgICAgICAgICAgICBkMTRjX21pbiA9IGQxNGMubHNbWzJdXSwKICAgICAgICAgICAgICAgICAgIGQxNGNfbWF4ID0gZDE0Yy5sc1tbM11dLAogICAgICAgICAgICAgICAgICAgbHlyX2JvdCA9IGMoMTAsIDIwLCAzMCksCiAgICAgICAgICAgICAgICAgICBQTWVjbyA9IFBNZWNvLAogICAgICAgICAgICAgICAgICAgUE0gPSBzdWJzdHIoUE1lY28sIDEsIDIpLAogICAgICAgICAgICAgICAgICAgRUNPID0gc3Vic3RyKFBNZWNvLCAzLCA0KSwKICAgICAgICAgICAgICAgICAgIHllYXIgPSAyMDAxKQogIHJldHVybihkZikKfSkpCiMgam9pbgpzcmEuMTkuMDEuaW5jIDwtIHJiaW5kKHNyYS4xOS4wMS5pbmMuZGYsIHNyYS4yMDE5LmluYy5kZikKCiMgcGxvdApzcmEuMTkuMDEuaW5jICU+JQogIG11dGF0ZShQTWVjb19kZXB0aCA9IHBhc3RlMChQTWVjbywgbHlyX2JvdCksCiAgICAgICAgIGRlcHRoID0gZmFjdG9yKGx5cl9ib3QpLAogICAgICAgICBlY28gPSBmYWN0b3IoaWZlbHNlKEVDTyA9PSAicHAiLCAid2FybSIsCiAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoRUNPID09ICJ3ZiIsICJjb29sIiwgImNvbGQiKSksCiAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSBjKCJ3YXJtIiwgImNvb2wiLCAiY29sZCIpKSwKICAgICAgICAgcG0gPSBpZmVsc2UoUE0gPT0gIkFOIiwgImFuZGVzaXRlIiwKICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKFBNID09ICJCUyIsICJiYXNhbHQiLCAiZ3Jhbml0ZSIpKSkgJT4lCiAgZ2dwbG90KC4sIGFlcyh5ZWFyLCBkMTRjKSkgKwogIGdlb21fcGF0aChkYXRhID0gYXRtLjE0YykgKwogIGdlb21fcG9pbnQoYWVzKGNvbG9yID0gZWNvLCBzaGFwZSA9IGVjbyksIHNpemUgPSAzKSArCiAgZ2VvbV9wb2ludChkYXRhID0gc3JhLjIwMTkuaW5jLkwuZGYsIGFlcyhjb2xvciA9IGVjbyksIHNoYXBlID0gOCwgc2l6ZSA9IDMsIHNob3cubGVnZW5kID0gRkFMU0UpICsKICBnZW9tX3BhdGgoYWVzKGNvbG9yID0gZWNvLCBncm91cCA9IFBNZWNvKSwgYWxwaGEgPSAwLjMpICsKICBnZW9tX2Vycm9yYmFyKAogICAgYWVzKHltaW4gPSBkMTRjX21pbiwgCiAgICAgICAgeW1heCA9IGQxNGNfbWF4LAogICAgICAgIGNvbG9yID0gZWNvKSwgCiAgICB3aWR0aCA9IC41KSArCiAgZ2VvbV9lcnJvcmJhcigKICAgIGRhdGEgPSBzcmEuMjAxOS5pbmMuTC5kZiwKICAgIGFlcyh5bWluID0gZDE0Y19taW4sIAogICAgICAgIHltYXggPSBkMTRjX21heCwKICAgICAgICBjb2xvciA9IGVjbyksIAogICAgd2lkdGggPSAuNSkgKwogIHNjYWxlX3NoYXBlX21hbnVhbChuYW1lID0gIkVjb3N5c3RlbSIsCiAgICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9IGMoIndhcm0iID0gMTUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJjb29sIiA9IDE2LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiY29sZCIgPSAxNykpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGltaXRzID0gYygtNDAsIDE3MCkpICsKICBmYWNldF9ncmlkKHJvd3MgPSB2YXJzKHBtKSwgY29scyA9IHZhcnMoZGVwdGgpKSArCiAgeWxhYihleHByZXNzaW9uKERlbHRhKicnXjE0KidDICjigLApJykpICsKICB4bGFiKCJZZWFyIikgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKHBhbmVsLmdyaWQgPSBlbGVtZW50X2JsYW5rKCkpCgojIHBsb3QgaW5jIGFuZCBidWxrIHRvZ2V0aGVyLCBieSBkZXB0aApzcmEudHMuYWxsIDwtIHNyYS4xOS4wMS4wOSAlPiUKICBmaWx0ZXIobHlyX2JvdCA8IDMxKSAlPiUKICBzZWxlY3QoWWVhciwgUE0sIEVDTywgUE1lY28sIGx5cl9ib3QsIGQxNGMsIGQxNGNfc2QpICU+JQogIG11dGF0ZShUeXBlID0gImJ1bGsiLAogICAgICAgICBkMTRjX3UgPSBkMTRjICsgZDE0Y19zZCwKICAgICAgICAgZDE0Y19sID0gZDE0YyAtIGQxNGNfc2QsCiAgICAgICAgIHllYXIgPSBhcy5udW1lcmljKGFzLmNoYXJhY3RlcihZZWFyKSkpICU+JQogIHNlbGVjdCgtZDE0Y19zZCwgLVllYXIpICU+JQogIGJpbmRfcm93cyguLAogICAgICAgICAgICBzcmEuMTkuMDEuaW5jICU+JQogICAgICAgICAgICAgIHNlbGVjdCh5ZWFyLCBQTSwgRUNPLCBQTWVjbywgbHlyX2JvdCwgZDE0YywgZDE0Y19taW4sIGQxNGNfbWF4KSAlPiUKICAgICAgICAgICAgICByZW5hbWUoZDE0Y19sID0gZDE0Y19taW4sCiAgICAgICAgICAgICAgICAgICAgIGQxNGNfdSA9IGQxNGNfbWF4KSAlPiUKICAgICAgICAgICAgICBtdXRhdGUoVHlwZSA9ICJpbmMiKQogICkgJT4lCiAgbXV0YXRlKGRlcHRoID0gZmFjdG9yKGx5cl9ib3QpLAogICAgICAgICBlY28gPSBmYWN0b3IoaWZlbHNlKEVDTyA9PSAicHAiLCAid2FybSIsCiAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoRUNPID09ICJ3ZiIsICJjb29sIiwgImNvbGQiKSksCiAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSBjKCJ3YXJtIiwgImNvb2wiLCAiY29sZCIpKSwKICAgICAgICAgcG0gPSBpZmVsc2UoUE0gPT0gIkFOIiwgImFuZGVzaXRlIiwKICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKFBNID09ICJCUyIsICJiYXNhbHQiLCAiZ3Jhbml0ZSIpKSwKICAgICAgICAgZWNvVHlwZSA9IHBhc3RlMChlY28sICIgKCIsIFR5cGUsICIpIikpCgojIFBsb3QgYnkgZGVwdGgKcGxvdC50cy5meCA8LSBmdW5jdGlvbihkZikgewogIGRmICU+JQogICAgZmlsdGVyKGQxNGMgPiAtMjAwKSAlPiUKICAgIGZpbHRlcih5ZWFyICE9IDIwMDkpICU+JQogICAgZ2dwbG90KC4sIGFlcyh5ZWFyLCBkMTRjKSkgKwogICAgZ2VvbV9wYXRoKGRhdGEgPSBhdG0uMTRjKSArCiAgICBnZW9tX3BvaW50KGFlcyhjb2xvciA9IHBtLCBzaGFwZSA9IGVjb1R5cGUpLCBzaXplID0gMykgKwogICAgZ2VvbV9wYXRoKGFlcyhjb2xvciA9IHBtLCBsaW5ldHlwZSA9IFR5cGUpLCBhbHBoYSA9IDAuMykgKwogICAgZ2VvbV9lcnJvcmJhcigKICAgICAgYWVzKHltaW4gPSBkMTRjX2wsIAogICAgICAgICAgeW1heCA9IGQxNGNfdSwKICAgICAgICAgIGNvbG9yID0gcG0pLCAKICAgICAgd2lkdGggPSAuNSkgKwogICAgc2NhbGVfY29sb3JfbWFudWFsKG5hbWUgPSAiUGFyZW50IG1hdGVyaWFsIiwKICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSBjKCJhbmRlc2l0ZSIgPSAiYmx1ZSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImJhc2FsdCIgPSAicmVkIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiZ3Jhbml0ZSIgPSAiZGFya2dyYXkiKSkgKwogICAgc2NhbGVfc2hhcGVfbWFudWFsKG5hbWUgPSAiRWNvc3lzdGVtICh0eXBlKSIsCiAgICAgICAgICAgICAgICAgICAgICAgdmFsdWVzID0gYygid2FybSAoaW5jKSIgPSAwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImNvb2wgKGluYykiID0gMSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJjb2xkIChpbmMpIiA9IDIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAid2FybSAoYnVsaykiID0gMTUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiY29vbCAoYnVsaykiID0gMTYsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiY29sZCAoYnVsaykiID0gMTcpKSArCiAgICBmYWNldF9ncmlkKHJvd3MgPSB2YXJzKGVjbyksIGNvbHMgPSB2YXJzKHBtKSkgKwogICAgeWxhYihleHByZXNzaW9uKERlbHRhKicnXjE0KidDICjigLApJykpICsKICAgIHhsYWIoIlllYXIiKSArCiAgICB0aGVtZV9idygpICsKICAgIHRoZW1lKHBhbmVsLmdyaWQgPSBlbGVtZW50X2JsYW5rKCkpCn0KCiMgcGxvdHMKbGFwcGx5KHNwbGl0KHNyYS50cy5hbGwsIHNyYS50cy5hbGwkZGVwdGgpLCBwbG90LnRzLmZ4KQoKIyAjIHRvIHNhdmUKIyBmb3IoaSBpbiAxOjMpIGdnc2F2ZShwYXN0ZTAoaSwgIi5wZGYiKSwgbGFwcGx5KHNwbGl0KHNyYS50cy5hbGwsIHNyYS50cy5hbGwkZGVwdGgpLCBwbG90LnRzLmZ4KVtbaV1dKQpgYGAKPioqRmlnLiBgciB7ZmlnLm59YC4gQ2hhbmdlIGluICRcRGVsdGEkXjE0XkMgb2YgYnVsayBzb2lsIChwYW5lbCBhKSBhbmQgcmVzcGlyZWQgQ09+Mn4gKHBhbmVsIGIpIG92ZXIgdGltZSByZWxhdGl2ZSB0byB0aGUgYXRtb3NwaGVyZSoqCgo+KkNhcHRpb246KiBQb2ludHMgZm9yIDIwMTkgc2FtcGxlcyBzaG93IHRoZSBtZWFuICRcRGVsdGEkXjE0XkMgdmFsdWVzIGF0IHRoZSBtZWFzdXJlZCBkZXB0aHMuIFBvaW50cyBmb3IgMjAwMSBhbmQgMjAwOSAoYnVsayBvbmx5KSBzYW1wbGVzIGFyZSBzcGxpbmUtZml0dGVkIGVzdGltYXRlcyBvZiAkXERlbHRhJF4xNF5DIHByZWRpY3RlZCBmb3IgdGhlIHNhbWUgZGVwdGggaW50ZXJ2YWxzIGFzIG1lYXN1cmVkIGluIDIwMTkuIEVycm9yIGJhcnMgZm9yIGJ1bGsgc2FtcGxlcyBpbiBwYW5lbCAoYSkgc2hvdyDCsSAxIHN0YW5kYXJkIGRldmlhdGlvbiBvZiB0aGUgbWVhbiBvZiB0aHJlZSByZXBsaWNhdGUgcHJvZmlsZXMgZm9yIDIwMDEgYW5kIDIwMTkgc2FtcGxlcyAob25seSBhIHNpbmdsZSBwcm9maWxlIHdhcyBhbmFseXplZCBpbiAyMDA5KTsgZXJyb3IgYmFycyBmb3IgaW5jdWJhdGlvbiBzYW1wbGVzIGluIHBhbmVsIChiKSBzaG93IHRoZSB2YWx1ZXMgb2YgdGhlIHR3byByZXBzLCB3aGlsZSB0aGUgcG9pbnQgcmVwcmVzZW50cyB0aGUgbWVhbi4gCj4qTkI6IE9ubHkgdHdvIGRlcHRoIGludGVydmFscyB3ZXJlIG1lYXN1cmVkIGF0IHRoZSBjb29sIGFuZCBjb2xkIGFuZGVzaXRlIHNpdGVzIChtYXggZGVwdGggb2YgMjcgYW5kIDI4IGNtLCByZXNwZWN0aXZlbHkpLCBzbyBsaW5lYXIgZXh0cmFwb2xhdGlvbiAodXNpbmcgdGhlIHNsb3BlIG9mIHRoZSBsYXN0IDFjbSBzcGxpbmUtZml0dGVkIGRlcHRoIGluY3JlbWVudCkgd2FzIHVzZWQgdG8gZXh0ZW5kIHRoZSBwcm9maWxlcyB0byAzMCBjbS4qCgpgYGB7ciBtaW4tZGF0YS1yYXMxOH0KIyBsb2FkIGRhdGEKcmFzMTguZnJjIDwtIHJlYWRfZXhjZWwoIi9Vc2Vycy9qZWZmL3NyYS10cy9kYXRhL2V4dGVybmFsL3NyYV9yYXNfc3VtL3NpZXJyYV9kYXRhX3N1bW1hcnlfMjAyMC54bHN4IiwKICAgICAgICAgICAgICAgICAgICAgICAgc2hlZXQgPSAiMjAwOV9mcmFjdGlvbl9kYXRhIikKCiMgc2VsZWN0IG9ubHkgbWluIGNvbHMgYW5kIHBpdm90IGxvbmdlcgpyYXMxOF8yIDwtIHJhczE4LnN1bSAlPiUKICBzZWxlY3QoYEZlZCAoZy9rZylgLCBgRmVvIChnL2tnKWAsIGBBbG8gKGcva2cpYCwgYEFscCAoZy9rZylgLCBgdG9wIG1pbmVyYWxgLCBgYm90dG9tIG1pbmVyYWxgLCBwcm9fbmFtZSkgJT4lIAogIHJlbmFtZShseXJfdG9wID0gYHRvcCBtaW5lcmFsYCwKICAgICAgICAgbHlyX2JvdCA9IGBib3R0b20gbWluZXJhbGApICU+JQogIHBpdm90X2xvbmdlcihjb2xzID0gYyhgRmVkIChnL2tnKWAsIAogICAgICAgICAgICAgICAgICAgICAgICBgRmVvIChnL2tnKWAsIAogICAgICAgICAgICAgICAgICAgICAgICBgQWxvIChnL2tnKWAsIAogICAgICAgICAgICAgICAgICAgICAgICBgQWxwIChnL2tnKWApLCAKICAgICAgICAgICAgICAgbmFtZXNfdG8gPSAibWlucyIsIHZhbHVlc190byA9ICJjb25jIikgJT4lCiAgZGF0YS5mcmFtZSgpCgojIENhbGN1bGF0ZSBtaW4gc3RvY2tzCnJhczE4XzMgPC0gcmFzMTguc3VtICU+JQogIHNlbGVjdChgRmVkIChnL2tnKWAsIGBGZW8gKGcva2cpYCwgYEFsbyAoZy9rZylgLCBgQWxwIChnL2tnKWAsIGB0b3AgbWluZXJhbGAsIGBib3R0b20gbWluZXJhbGAsIHByb19uYW1lLCBCRF9nX2NtXzMsIFNvaWxfZmluZWZyYWN0aW9uLCBUaGlja25lc3NfY20pICU+JSAKICByZW5hbWUobHlyX3RvcCA9IGB0b3AgbWluZXJhbGAsCiAgICAgICAgIGx5cl9ib3QgPSBgYm90dG9tIG1pbmVyYWxgKSAlPiUKICBwaXZvdF9sb25nZXIoY29scyA9IGMoYEZlZCAoZy9rZylgLCAKICAgICAgICAgICAgICAgICAgICAgICAgYEZlbyAoZy9rZylgLCAKICAgICAgICAgICAgICAgICAgICAgICAgYEFsbyAoZy9rZylgLCAKICAgICAgICAgICAgICAgICAgICAgICAgYEFscCAoZy9rZylgKSwgCiAgICAgICAgICAgICAgIG5hbWVzX3RvID0gIm1pbnMiLCB2YWx1ZXNfdG8gPSAiY29uYyIpICU+JQogIG11dGF0ZShtYXNzID0gVGhpY2tuZXNzX2NtICogQkRfZ19jbV8zICogU29pbF9maW5lZnJhY3Rpb24gKiAxMCwKICAgICAgICAgbWluX3N0b2NrID0gY29uYyAqIG1hc3MgKiAxMF4tMikgJT4lCiAgZGF0YS5mcmFtZSgpCnJhczE4XzMubHMgPC0gbGFwcGx5KHNwbGl0KHJhczE4XzMsIHJhczE4XzMkbWlucyksIGZ1bmN0aW9uKGRmKSB7CiAgbGFwcGx5KHNwbGl0KGRmLCBkZiRwcm9fbmFtZSksIGZ1bmN0aW9uKHgpIHsKICAgIHggPC0geFtvcmRlcih4JGx5cl9ib3QpLCBdCiAgICAjIGNhbGMgY210diBtaW4gc3RvY2sKICAgIHgkbWluX3N0b2NrX2NtdHYgPC0gTkEKICAgIGZvcihpIGluIHNlcV9hbG9uZyh4JGx5cl9ib3QpKSB7CiAgICAgIGlmKGkgPT0gMSkgewogICAgICAgIHgkbWluX3N0b2NrX2NtdHZbaV0gPC0geCRtaW5fc3RvY2tbaV0KICAgICAgfSBlbHNlIHsKICAgICAgICB4JG1pbl9zdG9ja19jbXR2W2ldIDwtIHgkbWluX3N0b2NrW2ldICsgeCRtaW5fc3RvY2tfY210dltpLTFdIAogICAgICB9CiAgICB9CiAgICB4JG1hc3NfY210diA8LSBOQQogICAgZm9yKGkgaW4gc2VxX2Fsb25nKHgkbHlyX2JvdCkpIHsKICAgICAgaWYoaSA9PSAxKSB7CiAgICAgICAgeCRtYXNzX2NtdHZbaV0gPC0geCRtYXNzW2ldCiAgICAgIH0gZWxzZSB7CiAgICAgICAgeCRtYXNzX2NtdHZbaV0gPC0geCRtYXNzW2ldICsgeCRtYXNzX2NtdHZbaS0xXSAKICAgICAgfQogICAgfQogICAgcmV0dXJuKHgpCiAgfSkKfSkKcmFzMThfMy5zcC5kZiA8LSBiaW5kX3Jvd3MobGFwcGx5KHJhczE4XzMubHMsIGZ1bmN0aW9uKGxzKSB7CiAgYmluZF9yb3dzKGxhcHBseShscywgZnVuY3Rpb24oeCkgewogICAgZGVwdGhzKHgpIDwtIHByb19uYW1lIH4gbHlyX3RvcCArIGx5cl9ib3QKICAgIHgubXBzIDwtIG1wc3BsaW5lKHgsIHZhci5uYW1lID0gIm1pbl9zdG9ja19jbXR2IikKICAgIHJldHVybih4Lm1wcyR2YXIuMWNtWzMwXSkKICB9KSwgLmlkID0gInByb19uYW1lIikgJT4lCiAgICBwaXZvdF9sb25nZXIoY29scyA9IGV2ZXJ5dGhpbmcoKSwgbmFtZXNfdG8gPSAicHJvX25hbWUiLCB2YWx1ZXNfdG8gPSAibWluX3N0b2NrX2NtdHYiKQp9KSwgLmlkID0gIm1pbiIpICU+JQogIG11dGF0ZShtaW4gPSBpZmVsc2UobWluID09ICJBbG8gKGcva2cpIiwgIkFsX294IiwKICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShtaW4gPT0gIkFscCAoZy9rZykiLCAiQWxfcHkiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShtaW4gPT0gIkZlZCAoZy9rZykiLCAiRmVfZGMiLCAiRmVfb3giKSkpLAogICAgICAgICBQTWVjbyA9IHN1YnN0cihwcm9fbmFtZSwgMSwgNCkpICU+JQogIHNlbGVjdCgtcHJvX25hbWUpCgojIG1hc3Mtd2VpZ2h0ZWQgY29uY2VudHJhdGlvbgpyYXMxOF80LnNwLmxzIDwtIGxhcHBseShyYXMxOF8zLmxzLCBmdW5jdGlvbihscykgewogIGNvbmMgPC0gdW5saXN0KGxhcHBseShscywgZnVuY3Rpb24oeCkgewogICAgZGVwdGhzKHgpIDwtIHByb19uYW1lIH4gbHlyX3RvcCArIGx5cl9ib3QKICAgIHgubXBzIDwtIG1wc3BsaW5lKHgsIHZhci5uYW1lID0gImNvbmMiKQogICAgZGYgPC0gZGF0YS5mcmFtZShjb25jID0geC5tcHMkdmFyLjFjbVsxOjMwXSwKICAgICAgICAgICAgICAgICAgICAgbHlyX2JvdCA9IHNlcSgxLCAzMCksCiAgICAgICAgICAgICAgICAgICAgIHByb19uYW1lID0gc3Vic3RyKHgubXBzJGlkY29sLCAxLCA0KSkKICAgIHJldHVybihzcGxpdChkZiwgZGYkcHJvX25hbWUpKQogICAgfSksIHJlY3Vyc2l2ZSA9IEZBTFNFKQogIG1hc3MgPC0gdW5saXN0KGxhcHBseShzZXFfYWxvbmcobHMpLCBmdW5jdGlvbihpKSB7CiAgICB4IDwtIGxzW1tpXV1bICwgYygibHlyX2JvdCIsICJtYXNzX2NtdHYiKV0KICAgIHQwIDwtIGRhdGEuZnJhbWUobWF0cml4KG5yb3cgPSAxLCBuY29sID0gbmNvbCh4KSkpCiAgICBuYW1lcyh0MCkgPC0gbmFtZXMoeCkKICAgIHQwIDwtIDAKICAgIHggPC0gcmJpbmQodDAsIHgpCiAgICBzcCA8LSBzcGxpbmUoeCwgbWV0aG9kID0gImh5bWFuIikgIyBmaXQgbW9ub3RvbmljIGN1YmljIHNwbGluZQogICAgc3Auc3MgPC0gc21vb3RoLnNwbGluZShzcCkgIyBjb252ZXJ0IHRvIGNsYXNzICJzcGxpbmUiIHdpdGggc21vb3RoLnNwbGluZSBmeG4KICAgIHN0ZCA8LSBzZXEoMCwgMzApICMgZGVwdGggaW4gY20KICAgIHNwIDwtIHByZWRpY3Qoc3Auc3MsIHN0ZCkgCiAgICBkZiA8LSBkYXRhLmZyYW1lKHNwKQogICAgY29sbmFtZXMoZGYpIDwtIGMoImx5cl9ib3QiLCAibWFzc19jbXR2IikKICAgIGRmJHByb19uYW1lIDwtIHN1YnN0cihuYW1lcyhscylbaV0sIDEsIDQpCiAgICBkZiA8LSBkZlstMSwgXQogICAgcmV0dXJuKHNwbGl0KGRmLCBkZiRwcm9fbmFtZSkpCiAgfSksIHJlY3Vyc2l2ZSA9IEZBTFNFKQogIHJldHVybihtYXBwbHkobWVyZ2UsCiAgICAgICAgICAgICAgICBtYXNzLAogICAgICAgICAgICAgICAgY29uYywKICAgICAgICAgICAgICAgIFNJTVBMSUZZID0gRkFMU0UpKQp9KQoKIyBjYWxjdWxhdGUgbWFzcy13ZWlnaHRlZCBjb25jIGZvciAwLTMwY20KcmFzMThfNC5zcC5kZiA8LSBiaW5kX3Jvd3MobGFwcGx5KHJhczE4XzQuc3AubHMsIGZ1bmN0aW9uKGxzKSB7CiAgYmluZF9yb3dzKGxhcHBseShscywgZnVuY3Rpb24oZGYpIHsKICAgIGRmIDwtIGRmW29yZGVyKGRmJGx5cl9ib3QpLCBdCiAgICBkZiRtYXNzIDwtIE5BCiAgICBmb3IgKGkgaW4gc2VxX2Fsb25nKGRmJG1hc3MpKSB7CiAgICAgIGlmIChpID09IDEpIHsKICAgICAgICBkZiRtYXNzW2ldIDwtIGRmJG1hc3NfY210dltpXQogICAgICB9IGVsc2UgewogICAgICAgIGRmJG1hc3NbaV0gPC0gZGYkbWFzc19jbXR2W2ldIC0gZGYkbWFzc19jbXR2W2ktMV0KICAgICAgfQogICAgfQogICAgZGYkbWFzc193dCA8LSBkZiRtYXNzL3N1bShkZiRtYXNzKQogICAgZGYkY29uY18zMF93dGQgPC0gZGYkbWFzc193dCAqIGRmJGNvbmMKICAgIHJldHVybihzdW0oZGYkY29uY18zMF93dGQpKQogIH0pLCAuaWQgPSAicHJvX25hbWUiKQp9KSwgLmlkID0gIm1pbiIpICU+JQogIHBpdm90X2xvbmdlcighbWluLCBuYW1lc190byA9ICJQTWVjbyIsIHZhbHVlc190byA9ICJjb25jIikgJT4lCiAgbXV0YXRlKG1pbiA9IGlmZWxzZShtaW4gPT0gIkFsbyAoZy9rZykiLCAiQWxfb3giLCAKICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShtaW4gPT0gIkFscCAoZy9rZykiLCAiQWxfcHkiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShtaW4gPT0gIkZlZCAoZy9rZykiLCAiRmVfZGMiLCAiRmVfb3giKSkpKQoKIyBtZXJnZSB3LyAxNEMgZGF0YQpzcmEuYWxsLjMwLm1pbi5jb25jLnd0ZCA8LSBtZXJnZShzcmEuMzAuYmxrLmluYy5kZiwgcmFzMThfNC5zcC5kZiwgYnkgPSAiUE1lY28iKSAlPiUKICBtdXRhdGUocG0gPSBpZmVsc2Uoc3Vic3RyKFBNZWNvLCAxLCAyKSA9PSAiQU4iLCAiYW5kZXNpdGUiLCAKICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKHN1YnN0cihQTWVjbywgMSwgMikgPT0gIkJTIiwgImJhc2FsdCIsICJncmFuaXRlIikpLAogICAgICAgICBlY28gPSBpZmVsc2Uoc3Vic3RyKFBNZWNvLCAzLCA0KSA9PSAicHAiLCAid2FybSIsIAogICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKHN1YnN0cihQTWVjbywgMywgNCkgPT0gIndmIiwgImNvb2wiLCAiY29sZCIpKSkKc2F2ZShzcmEuYWxsLjMwLm1pbi5jb25jLnd0ZCwgZmlsZSA9ICJzcmEuYWxsLjMwLm1pbi5jb25jLnd0ZC5SRGF0YSIpCgojIHNwbGluZSBmaXRzCiMgKHNob3VsZCBiZSBtYXNzLXdlaWdodGVkLi4uKQojIGFsc28gY2FsY3VsYXRlIGZvciAwLTMwY20KcmFzMTguc3BsaXQgPC0gc3BsaXQocmFzMThfMiwgcmFzMThfMiRtaW5zKQpyYXMxOC5zcCA8LSBsYXBwbHkocmFzMTguc3BsaXQsIGZ1bmN0aW9uKGRmKSB7CiAgbHMgPC0gbGFwcGx5KHNwbGl0KGRmLCBkZiRwcm9fbmFtZSksIGZ1bmN0aW9uKHgpIHsKICAgIGRlcHRocyh4KSA8LSBwcm9fbmFtZSB+IGx5cl90b3AgKyBseXJfYm90CiAgICB4Lm1wcyA8LSBtcHNwbGluZSh4LCB2YXIubmFtZSA9ICJjb25jIiwgZCA9IHQoc2VxKDAsIDEwMCwgMTApKSkKICAgIHJldHVybih4Lm1wcyR2YXIuc3RkKQogIH0pCiAgbmFtZXMobHMpIDwtIHVuaXF1ZShkZiRwcm9fbmFtZSkKICByZXR1cm4obHMpCn0pCm5hbWVzKHJhczE4LnNwKSA8LSBjKCJBbF9veCIsICJBbF9weSIsICJGZV9kYyIsICJGZV9veCIpCnJhczE4LnNwLmRmIDwtIGRhdGEuZnJhbWUocmVkdWNlKGxhcHBseShzZXFfYWxvbmcocmFzMTguc3ApLCBmdW5jdGlvbihpKSB7CiAgICBkZiA8LSBkYXRhLmZyYW1lKHQoYmluZF9yb3dzKHJhczE4LnNwW1tpXV0pKSkKICAgIG5hbWVzKGRmKSA8LSB1bmlxdWUocmFzMTguc3VtJHByb19uYW1lKQogICAgZGYkZGVwdGggPC0gcm93bmFtZXMoZGYpCiAgICByZXR1cm4oZGYgJT4lCiAgICAgICAgICAgICBwaXZvdF9sb25nZXIoIWRlcHRoLCBuYW1lc190byA9ICJwcm9fbmFtZSIsIHZhbHVlc190byA9IG5hbWVzKHJhczE4LnNwKVtpXSkpCiAgfSksCiAgbGVmdF9qb2luLAogIGJ5ID0gYygiZGVwdGgiLCAicHJvX25hbWUiKQopKQpyYXMxOC5zcC5kZiA8LSByYXMxOC5zcC5kZlstd2hpY2gocmFzMTguc3AuZGYkZGVwdGggPT0gInNvaWwgZGVwdGgiKSwgXQpyYXMxOC5zcC5kZiRseXJfYm90IDwtIHJlcChzZXEoMTAsIDEwMCwgMTApLCBlYWNoID0gOSkKcmFzMTguc3AuZGYgPC0gcmFzMTguc3AuZGZbY29tcGxldGUuY2FzZXMocmFzMTguc3AuZGYpLCBdCnJhczE4LnNwLmRmJFBNIDwtIHN1YnN0cihyYXMxOC5zcC5kZiRwcm9fbmFtZSwgMSwgMikKcmFzMTguc3AuZGYkRUNPIDwtIHN1YnN0cihyYXMxOC5zcC5kZiRwcm9fbmFtZSwgMywgNCkKc2F2ZShyYXMxOC5zcC5kZiwgZmlsZSA9ICJyYXMxOC5zcC5kZi5SRGF0YSIpCgojIHJlc2hhcGUgc3JhLnRzLmFsbCB3LyBidWxrIGFuZCBpbmMgaW4gc2VwYXJhdGUgY29scwpubXMuaW5jLmJsazIgPC0gbm1zLmluYy5ibGsKbm1zLmluYy5ibGsyW1s0XV0gPC0gInllYXIiCnNyYS50cy5hbGwuYmxrLmluYyA8LSBtZXJnZShzcmEudHMuYWxsW3NyYS50cy5hbGwkVHlwZSA9PSAiYnVsayIsIF0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzcmEudHMuYWxsW3NyYS50cy5hbGwkVHlwZSA9PSAiaW5jIiwgYyhubXMuaW5jLmJsazIsICJkMTRjIiwgImQxNGNfdSIsICJkMTRjX2wiKV0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBieSA9IG5tcy5pbmMuYmxrMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1ZmZpeGVzID0gYygiX2J1bGsiLCAiX2luYyIpKSAlPiUKICBmaWx0ZXIoeWVhciAhPSAyMDA5KSAlPiUKICBtdXRhdGUoYmxrLmluYyA9IGQxNGNfYnVsayAtIGQxNGNfaW5jLAogICAgICAgICBibGsuaW5jLnNkID0gc3FydCgoZDE0Y191X2J1bGsgLSBkMTRjX2J1bGspXjIgKyBhcHBseShjYmluZChkMTRjX3VfaW5jLCBkMTRjX2xfaW5jKSwgMSwgdmFyKSkpCgojIGpvaW4gdy8gZDE0YwpzcmEuYWxsLm1pbiA8LSByYXMxOC5zcC5kZiAlPiUKICBtdXRhdGUocG0gPSBpZmVsc2UoUE0gPT0gIkFOIiwgImFuZGVzaXRlIiwgaWZlbHNlKFBNID09ICJCUyIsICJiYXNhbHQiLCAiZ3Jhbml0ZSIpKSwKICAgICAgICAgZWNvID0gaWZlbHNlKEVDTyA9PSAicHAiLCAid2FybSIsIGlmZWxzZShFQ08gPT0gIndmIiwgImNvb2wiLCAiY29sZCIpKSkgJT4lCiAgIyBtdXRhdGUoQWxfbm9uQ3J5cyA9IEFsX294IC0gQWxfcHksCiAgIyAgICAgICAgRmVfQ3J5cyA9IEZlX2RjIC0gRmVfb3gpICU+JQogIHNlbGVjdCgtUE0sIC1FQ08sIC1wcm9fbmFtZSkgJT4lCiAgbGVmdF9qb2luKHNyYS50cy5hbGwuYmxrLmluY1sgLCBjKCJwbSIsICJlY28iLCAibHlyX2JvdCIsICJ5ZWFyIiwgImQxNGNfYnVsayIsICJkMTRjX3VfYnVsayIsICJkMTRjX2luYyIsICJkMTRjX3VfaW5jIiwgImQxNGNfbF9pbmMiLCAiZDE0Y19sX2J1bGsiLCAiYmxrLmluYyIsICJibGsuaW5jLnNkIildLCAKICAgICAgICAgICAgLiwgCiAgICAgICAgICAgIGJ5ID0gYygicG0iLCAiZWNvIiwgImx5cl9ib3QiKSkgJT4lCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSBjKCJBbF9weSIsICJBbF9veCIsICJGZV9veCIsICJGZV9kYyIsIAogICAgICAgICAgICAgICAgICAgICAgICAjICJBbF9ub25DcnlzIiwgIkZlX0NyeXMiCiAgICAgICAgICAgICAgICAgICAgICAgICksIG5hbWVzX3RvID0gIm1pbiIsIHZhbHVlc190byA9ICJjb25jIikKCiMgQ3JlYXRlIG1pbi8xNGMgZGYgdy8gMC0zMGNtIDE0QyBkYXRhCnNyYS5hbGwuMzAubWluIDwtIG1lcmdlKHNyYS4zMC5ibGsuaW5jLmRmLCByYXMxOF8zLnNwLmRmLCBieSA9ICJQTWVjbyIpICU+JQogIG11dGF0ZShwbSA9IGlmZWxzZShzdWJzdHIoUE1lY28sIDEsIDIpID09ICJBTiIsICJhbmRlc2l0ZSIsIAogICAgICAgICAgICAgICAgICAgICBpZmVsc2Uoc3Vic3RyKFBNZWNvLCAxLCAyKSA9PSAiQlMiLCAiYmFzYWx0IiwgImdyYW5pdGUiKSksCiAgICAgICAgIGVjbyA9IGlmZWxzZShzdWJzdHIoUE1lY28sIDMsIDQpID09ICJwcCIsICJ3YXJtIiwgCiAgICAgICAgICAgICAgICAgICAgICBpZmVsc2Uoc3Vic3RyKFBNZWNvLCAzLCA0KSA9PSAid2YiLCAiY29vbCIsICJjb2xkIikpKQoKCiMgc2F2ZQpzYXZlKHNyYS5hbGwubWluLCBmaWxlID0gInNyYS5hbGwubWluLlJEYXRhIikKc2F2ZShzcmEuYWxsLjMwLm1pbiwgZmlsZSA9ICJzcmEuYWxsLjMwLm1pbi5SRGF0YSIpCmBgYAoKYGBge3IgcGxvdC1taW4tMTRjfQojIGJ1bGsKc3JhLmFsbC5taW4gJT4lCiAgbXV0YXRlKHBtRWNvRGVwdGggPSBwYXN0ZTAocG0sIGVjbywgbHlyX2JvdCksCiAgICAgICAgIGVjb1llYXIgPSBwYXN0ZTAoZWNvLCAiICgiLCB5ZWFyLCAiKSIpLAogICAgICAgICB3aWR0aCA9IGlmZWxzZShtaW4gPT0gIkFsX3B5IiB8IG1pbiA9PSAiRmVfb3giLCAuMywgMS41KSkgJT4lCiAgZmlsdGVyKHBtRWNvRGVwdGggIT0gImdyYW5pdGVjb2xkMzAiICYgcG1FY29EZXB0aCAhPSAiZ3Jhbml0ZWNvbGQyMCIpICU+JQogIGdncGxvdCguLCBhZXMoY29uYywgZDE0Y19idWxrKSkgKwogIGdlb21fcG9pbnQoYWVzKGNvbG9yID0gcG0sIHNoYXBlID0gZWNvWWVhciwgc2l6ZSA9IGRlcHRoKSkgKwogIGdlb21fZXJyb3JiYXIoCiAgICBhZXMoeW1pbiA9IGQxNGNfbF9idWxrLAogICAgICAgIHltYXggPSBkMTRjX3VfYnVsaywKICAgICAgICBjb2xvciA9IHBtLAogICAgICAgIHdpZHRoID0gd2lkdGgpKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKG5hbWUgPSAiUGFyZW50IG1hdGVyaWFsIiwKICAgICAgICAgICAgICAgICAgICAgdmFsdWVzID0gYygiYW5kZXNpdGUiID0gYW5kZXNpdGUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImJhc2FsdCIgPSBiYXNhbHQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImdyYW5pdGUiID0gZ3Jhbml0ZSkpICsKICBzY2FsZV9zaGFwZV9tYW51YWwobmFtZSA9ICJDbGltYXRlICh5ZWFyKSIsCiAgICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9IGMoIndhcm0gKDIwMDEpIiA9IDE1LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiY29vbCAoMjAwMSkiID0gMTYsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJjb2xkICgyMDAxKSIgPSAxNywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAid2FybSAoMjAxOSkiID0gMCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImNvb2wgKDIwMTkpIiA9IDEsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJjb2xkICgyMDE5KSIgPSAyKSkgKwogIHNjYWxlX3NpemVfbWFudWFsKG5hbWUgPSAiRGVwdGgiLAogICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9ICgzOjUpKSArCiAgZmFjZXRfd3JhcCh2YXJzKG1pbiksIHNjYWxlcyA9ICJmcmVlIikgKwogIHlsYWIoZXhwcmVzc2lvbignQnVsayAtIFJlc3BpcmVkICcqRGVsdGEqJydeMTQqJ0MgKOKAsCknKSkgKwogIHhsYWIoZXhwcmVzc2lvbignQ29uY2VudHJhdGlvbiAoZyBrZydeLTEqJyknKSkgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCkpCgojIGluYwpzcmEuYWxsLm1pbiAlPiUKICBtdXRhdGUocG1FY29EZXB0aCA9IHBhc3RlMChwbSwgZWNvLCBseXJfYm90KSwKICAgICAgICAgZWNvWWVhciA9IHBhc3RlMChlY28sICIgKCIsIHllYXIsICIpIiksCiAgICAgICAgIHdpZHRoID0gaWZlbHNlKG1pbiA9PSAiQWxfcHkiIHwgbWluID09ICJGZV9veCIsIC4zLCAxLjUpKSAlPiUKICBmaWx0ZXIocG1FY29EZXB0aCAhPSAiZ3Jhbml0ZWNvbGQzMCIgJiBwbUVjb0RlcHRoICE9ICJncmFuaXRlY29sZDIwIikgJT4lCiAgZmlsdGVyKGx5cl9ib3QgPT0gMzApICU+JQogIGdncGxvdCguLCBhZXMoY29uYywgZDE0Y19pbmMpKSArCiAgZ2VvbV9wb2ludChhZXMoY29sb3IgPSBwbSwgc2hhcGUgPSBlY29ZZWFyLCBzaXplID0gZGVwdGgpKSArCiAgZ2VvbV9lcnJvcmJhcigKICAgIGFlcyh5bWluID0gZDE0Y19sX2luYywKICAgICAgICB5bWF4ID0gZDE0Y191X2luYywKICAgICAgICBjb2xvciA9IHBtLAogICAgICAgIHdpZHRoID0gd2lkdGgpKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKG5hbWUgPSAiUGFyZW50IG1hdGVyaWFsIiwKICAgICAgICAgICAgICAgICAgICAgdmFsdWVzID0gYygiYW5kZXNpdGUiID0gYW5kZXNpdGUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImJhc2FsdCIgPSBiYXNhbHQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImdyYW5pdGUiID0gZ3Jhbml0ZSkpICsKICBzY2FsZV9zaGFwZV9tYW51YWwobmFtZSA9ICJDbGltYXRlICh5ZWFyKSIsCiAgICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9IGMoIndhcm0gKDIwMDEpIiA9IDE1LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiY29vbCAoMjAwMSkiID0gMTYsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJjb2xkICgyMDAxKSIgPSAxNywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAid2FybSAoMjAxOSkiID0gMCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImNvb2wgKDIwMTkpIiA9IDEsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJjb2xkICgyMDE5KSIgPSAyKSkgKwogIHNjYWxlX3NpemVfbWFudWFsKG5hbWUgPSAiRGVwdGgiLAogICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9ICgzOjUpKSArCiAgZmFjZXRfd3JhcCh2YXJzKG1pbiksIHNjYWxlcyA9ICJmcmVlIikgKwogIHlsYWIoZXhwcmVzc2lvbignQnVsayAtIFJlc3BpcmVkICcqRGVsdGEqJydeMTQqJ0MgKOKAsCknKSkgKwogIHhsYWIoZXhwcmVzc2lvbignQ29uY2VudHJhdGlvbiAoZyBrZydeLTEqJyknKSkgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCkpCgojIGJ1bGstaW5jCnNyYS5hbGwubWluICU+JQogIG11dGF0ZShwbUVjb0RlcHRoID0gcGFzdGUwKHBtLCBlY28sIGx5cl9ib3QpLAogICAgICAgICBlY29ZZWFyID0gcGFzdGUwKGVjbywgIiAoIiwgeWVhciwgIikiKSwKICAgICAgICAgd2lkdGggPSBpZmVsc2UobWluID09ICJBbF9weSIgfCBtaW4gPT0gIkZlX294IiwgLjMsIDEuNSkpICU+JQogIGZpbHRlcihwbUVjb0RlcHRoICE9ICJncmFuaXRlY29sZDMwIiAmIHBtRWNvRGVwdGggIT0gImdyYW5pdGVjb2xkMjAiKSAlPiUKICBnZ3Bsb3QoLiwgYWVzKGNvbmMsIGJsay5pbmMpKSArCiAgZ2VvbV9wb2ludChhZXMoY29sb3IgPSBwbSwgc2hhcGUgPSBlY29ZZWFyLCBzaXplID0gZGVwdGgpKSArCiAgZ2VvbV9lcnJvcmJhcigKICAgIGFlcyh5bWluID0gYmxrLmluYyAtIGJsay5pbmMuc2QsCiAgICAgICAgeW1heCA9IGJsay5pbmMgKyBibGsuaW5jLnNkLAogICAgICAgIGNvbG9yID0gcG0sCiAgICAgICAgd2lkdGggPSB3aWR0aCkpICsKICBzY2FsZV9jb2xvcl9tYW51YWwobmFtZSA9ICJQYXJlbnQgbWF0ZXJpYWwiLAogICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSBjKCJhbmRlc2l0ZSIgPSBhbmRlc2l0ZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiYmFzYWx0IiA9IGJhc2FsdCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiZ3Jhbml0ZSIgPSBncmFuaXRlKSkgKwogIHNjYWxlX3NoYXBlX21hbnVhbChuYW1lID0gIkNsaW1hdGUgKHllYXIpIiwKICAgICAgICAgICAgICAgICAgICAgdmFsdWVzID0gYygid2FybSAoMjAwMSkiID0gMTUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJjb29sICgyMDAxKSIgPSAxNiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImNvbGQgKDIwMDEpIiA9IDE3LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJ3YXJtICgyMDE5KSIgPSAwLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiY29vbCAoMjAxOSkiID0gMSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImNvbGQgKDIwMTkpIiA9IDIpKSArCiAgc2NhbGVfc2l6ZV9tYW51YWwobmFtZSA9ICJEZXB0aCIsCiAgICAgICAgICAgICAgICAgICAgdmFsdWVzID0gKDM6NSkpICsKICBmYWNldF93cmFwKHZhcnMobWluKSwgc2NhbGVzID0gImZyZWUiKSArCiAgeWxhYihleHByZXNzaW9uKCdCdWxrIC0gUmVzcGlyZWQgJypEZWx0YSonJ14xNConQyAo4oCwKScpKSArCiAgeGxhYihleHByZXNzaW9uKCdDb25jZW50cmF0aW9uIChnIGtnJ14tMSonKScpKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUocGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSkKCiMgRmVfZGMgYWxvbmUKIyMjIyMKIyB3YXJtCnNyYS5hbGwubWluICU+JQogIGZpbHRlcihlY28gPT0gIndhcm0iICYgbWluID09ICJGZV9kYyIpICU+JQogIG11dGF0ZShlY29ZZWFyID0gcGFzdGUwKGVjbywgIiAoIiwgeWVhciwgIikiKSkgJT4lCiAgZ2dwbG90KC4sIGFlcyhjb25jLCBibGsuaW5jKSkgKwogIGdlb21fcG9pbnQoYWVzKGNvbG9yID0gcG0sIHNoYXBlID0gZWNvWWVhciwgc2l6ZSA9IGRlcHRoKSkgKwogIGdlb21fZXJyb3JiYXIoCiAgICBhZXMoeW1pbiA9IGJsay5pbmMgLSBibGsuaW5jLnNkLAogICAgICAgIHltYXggPSBibGsuaW5jICsgYmxrLmluYy5zZCwKICAgICAgICBjb2xvciA9IHBtKSwKICAgICAgICB3aWR0aCA9IDEuNSkgKwogIHNjYWxlX2NvbG9yX21hbnVhbChuYW1lID0gIlBhcmVudCBtYXRlcmlhbCIsCiAgICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9IGMoImFuZGVzaXRlIiA9IGFuZGVzaXRlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJiYXNhbHQiID0gYmFzYWx0LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJncmFuaXRlIiA9IGdyYW5pdGUpKSArCiAgc2NhbGVfc2hhcGVfbWFudWFsKG5hbWUgPSAiQ2xpbWF0ZSAoeWVhcikiLAogICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSBjKCJ3YXJtICgyMDAxKSIgPSAxNSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAid2FybSAoMjAxOSkiID0gMCkpICsKICBzY2FsZV9zaXplX21hbnVhbChuYW1lID0gIkRlcHRoIiwKICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSAoMzo1KSkgKwogIGZhY2V0X3dyYXAodmFycyhtaW4pLCBzY2FsZXMgPSAiZnJlZSIpICsKICB5bGFiKGV4cHJlc3Npb24oJ0J1bGsgLSBSZXNwaXJlZCAnKkRlbHRhKicnXjE0KidDICjigLApJykpICsKICB4bGFiKGV4cHJlc3Npb24oJ0NvbmNlbnRyYXRpb24gKGcga2cnXi0xKicpJykpICsKICB0aGVtZV9idygpICsKICB0aGVtZShwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpKQoKIyBjb29sICsgY29sZApzcmEuYWxsLm1pbiAlPiUKICBmaWx0ZXIoZWNvICE9ICJ3YXJtIiAmIG1pbiA9PSAiRmVfZGMiKSAlPiUKICBtdXRhdGUocG1FY29EZXB0aCA9IHBhc3RlMChwbSwgZWNvLCBseXJfYm90KSwKICAgICAgICAgZWNvWWVhciA9IHBhc3RlMChlY28sICIgKCIsIHllYXIsICIpIikpICU+JQogIGZpbHRlcihwbUVjb0RlcHRoICE9ICJncmFuaXRlY29sZDMwIiAmIHBtRWNvRGVwdGggIT0gImdyYW5pdGVjb2xkMjAiKSAlPiUKICBnZ3Bsb3QoLiwgYWVzKGNvbmMsIGJsay5pbmMpKSArCiAgZ2VvbV9wb2ludChhZXMoY29sb3IgPSBwbSwgc2hhcGUgPSBlY29ZZWFyLCBzaXplID0gZGVwdGgpKSArCiAgZ2VvbV9lcnJvcmJhcigKICAgIGFlcyh5bWluID0gYmxrLmluYyAtIGJsay5pbmMuc2QsCiAgICAgICAgeW1heCA9IGJsay5pbmMgKyBibGsuaW5jLnNkLAogICAgICAgIGNvbG9yID0gcG0pLAogICAgICAgIHdpZHRoID0gLjUpICsKICBzY2FsZV9jb2xvcl9tYW51YWwobmFtZSA9ICJQYXJlbnQgbWF0ZXJpYWwiLAogICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSBjKCJhbmRlc2l0ZSIgPSBhbmRlc2l0ZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiYmFzYWx0IiA9IGJhc2FsdCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiZ3Jhbml0ZSIgPSBncmFuaXRlKSkgKwogIHNjYWxlX3NoYXBlX21hbnVhbChuYW1lID0gIkNsaW1hdGUgKHllYXIpIiwKICAgICAgICAgICAgICAgICAgICAgdmFsdWVzID0gYygiY29vbCAoMjAwMSkiID0gMTYsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJjb2xkICgyMDAxKSIgPSAxNywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiY29vbCAoMjAxOSkiID0gMSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImNvbGQgKDIwMTkpIiA9IDIpKSArCiAgc2NhbGVfc2l6ZV9tYW51YWwobmFtZSA9ICJEZXB0aCIsCiAgICAgICAgICAgICAgICAgICAgdmFsdWVzID0gKDM6NSkpICsKICBmYWNldF93cmFwKHZhcnMobWluKSwgc2NhbGVzID0gImZyZWUiKSArCiAgeWxhYihleHByZXNzaW9uKCdCdWxrIC0gUmVzcGlyZWQgJypEZWx0YSonJ14xNConQyAo4oCwKScpKSArCiAgeGxhYihleHByZXNzaW9uKCdDb25jZW50cmF0aW9uIChnIGtnJ14tMSonKScpKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUocGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSkKIyMjIyMKCiMjIGJ5IGRlcHRoCiMjIyMjCiMgIyAxMCBjbQojIHNyYS5hbGwubWluICU+JQojICAgbXV0YXRlKGVjb1llYXIgPSBwYXN0ZTAoZWNvLCAiICgiLCB5ZWFyLCAiKSIpLAojICAgICAgICAgIHdpZHRoID0gaWZlbHNlKG1pbiA9PSAiQWxfcHkiIHwgbWluID09ICJGZV9veCIsIC4zLCAxLjUpKSAlPiUKIyAgIGZpbHRlcihseXJfYm90ID09IDEwKSAlPiUKIyAgIGdncGxvdCguLCBhZXMoY29uYywgYmxrLmluYykpICsKIyAgIGdlb21fcG9pbnQoYWVzKGNvbG9yID0gcG0sIHNoYXBlID0gZWNvWWVhciksIHNpemUgPSAzKSArCiMgICBnZW9tX2Vycm9yYmFyKAojICAgICBhZXMoeW1pbiA9IGJsay5pbmMgLSBibGsuaW5jLnNkLAojICAgICAgICAgeW1heCA9IGJsay5pbmMgKyBibGsuaW5jLnNkLAojICAgICAgICAgY29sb3IgPSBwbSwKIyAgICAgICAgIHdpZHRoID0gd2lkdGgpKSArCiMgICBzY2FsZV9jb2xvcl9tYW51YWwobmFtZSA9ICJQYXJlbnQgbWF0ZXJpYWwiLAojICAgICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9IGMoImFuZGVzaXRlIiA9IGFuZGVzaXRlLAojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImJhc2FsdCIgPSBiYXNhbHQsCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiZ3Jhbml0ZSIgPSBncmFuaXRlKSkgKwojICAgc2NhbGVfc2hhcGVfbWFudWFsKG5hbWUgPSAiQ2xpbWF0ZSAoeWVhcikiLAojICAgICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9IGMoIndhcm0gKDIwMDEpIiA9IDE1LCAKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJjb29sICgyMDAxKSIgPSAxNiwgCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiY29sZCAoMjAwMSkiID0gMTcsCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAid2FybSAoMjAxOSkiID0gMCwgCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiY29vbCAoMjAxOSkiID0gMSwgCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiY29sZCAoMjAxOSkiID0gMikpICsKIyAgIGZhY2V0X3dyYXAodmFycyhtaW4pLCBzY2FsZXMgPSAiZnJlZSIpICsKIyAgIHlsYWIoZXhwcmVzc2lvbignQnVsayAtIFJlc3BpcmVkICcqRGVsdGEqJydeMTQqJ0MgKOKAsCknKSkgKwojICAgeGxhYihleHByZXNzaW9uKCdDb25jZW50cmF0aW9uIChnIGtnJ14tMSonKScpKSArCiMgICB0aGVtZV9idygpICsKIyAgIHRoZW1lKHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCkpCiMgCiMgIyAyMCBjbQojIHNyYS5hbGwubWluICU+JQojICAgbXV0YXRlKHBtRWNvRGVwdGggPSBwYXN0ZTAocG0sIGVjbywgbHlyX2JvdCksCiMgICAgICAgICAgZWNvWWVhciA9IHBhc3RlMChlY28sICIgKCIsIHllYXIsICIpIiksCiMgICAgICAgICAgd2lkdGggPSBpZmVsc2UobWluID09ICJBbF9weSIgfCBtaW4gPT0gIkZlX294IiwgLjMsIDEuNSkpICU+JQojICAgZmlsdGVyKHBtRWNvRGVwdGggIT0gImdyYW5pdGVjb2xkMjAiKSAlPiUKIyAgIGZpbHRlcihseXJfYm90ID09IDIwKSAlPiUKIyAgIGdncGxvdCguLCBhZXMoY29uYywgYmxrLmluYykpICsKIyAgIGdlb21fcG9pbnQoYWVzKGNvbG9yID0gcG0sIHNoYXBlID0gZWNvWWVhciksIHNpemUgPSAzKSArCiMgICBnZW9tX2Vycm9yYmFyKAojICAgICBhZXMoeW1pbiA9IGJsay5pbmMgLSBibGsuaW5jLnNkLAojICAgICAgICAgeW1heCA9IGJsay5pbmMgKyBibGsuaW5jLnNkLAojICAgICAgICAgY29sb3IgPSBwbSwKIyAgICAgICAgIHdpZHRoID0gd2lkdGgpKSArCiMgICBzY2FsZV9jb2xvcl9tYW51YWwobmFtZSA9ICJQYXJlbnQgbWF0ZXJpYWwiLAojICAgICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9IGMoImFuZGVzaXRlIiA9IGFuZGVzaXRlLAojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImJhc2FsdCIgPSBiYXNhbHQsCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiZ3Jhbml0ZSIgPSBncmFuaXRlKSkgKwojICAgc2NhbGVfc2hhcGVfbWFudWFsKG5hbWUgPSAiQ2xpbWF0ZSAoeWVhcikiLAojICAgICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9IGMoIndhcm0gKDIwMDEpIiA9IDE1LCAKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJjb29sICgyMDAxKSIgPSAxNiwgCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiY29sZCAoMjAwMSkiID0gMTcsCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAid2FybSAoMjAxOSkiID0gMCwgCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiY29vbCAoMjAxOSkiID0gMSwgCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiY29sZCAoMjAxOSkiID0gMikpICsKIyAgIGZhY2V0X3dyYXAodmFycyhtaW4pLCBzY2FsZXMgPSAiZnJlZSIpICsKIyAgIHlsYWIoZXhwcmVzc2lvbignQnVsayAtIFJlc3BpcmVkICcqRGVsdGEqJydeMTQqJ0MgKOKAsCknKSkgKwojICAgeGxhYihleHByZXNzaW9uKCdDb25jZW50cmF0aW9uIChnIGtnJ14tMSonKScpKSArCiMgICB0aGVtZV9idygpICsKIyAgIHRoZW1lKHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCkpCiMgCiMgIyAzMCBjbQojIHNyYS5hbGwubWluICU+JQojICAgbXV0YXRlKHBtRWNvRGVwdGggPSBwYXN0ZTAocG0sIGVjbywgbHlyX2JvdCksCiMgICAgICAgICAgZWNvWWVhciA9IHBhc3RlMChlY28sICIgKCIsIHllYXIsICIpIiksCiMgICAgICAgICAgd2lkdGggPSBpZmVsc2UobWluID09ICJBbF9weSIgfCBtaW4gPT0gIkZlX294IiwgLjMsIDEuNSkpICU+JQojICAgZmlsdGVyKHBtRWNvRGVwdGggIT0gImdyYW5pdGVjb2xkMzAiKSAlPiUKIyAgIGZpbHRlcihseXJfYm90ID09IDMwKSAlPiUKIyAgIGdncGxvdCguLCBhZXMoY29uYywgYmxrLmluYykpICsKIyAgIGdlb21fcG9pbnQoYWVzKGNvbG9yID0gcG0sIHNoYXBlID0gZWNvWWVhciksIHNpemUgPSAzKSArCiMgICBnZW9tX2Vycm9yYmFyKAojICAgICBhZXMoeW1pbiA9IGJsay5pbmMgLSBibGsuaW5jLnNkLAojICAgICAgICAgeW1heCA9IGJsay5pbmMgKyBibGsuaW5jLnNkLAojICAgICAgICAgY29sb3IgPSBwbSwKIyAgICAgICAgIHdpZHRoID0gd2lkdGgpKSArCiMgICBzY2FsZV9jb2xvcl9tYW51YWwobmFtZSA9ICJQYXJlbnQgbWF0ZXJpYWwiLAojICAgICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9IGMoImFuZGVzaXRlIiA9IGFuZGVzaXRlLAojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImJhc2FsdCIgPSBiYXNhbHQsCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiZ3Jhbml0ZSIgPSBncmFuaXRlKSkgKwojICAgc2NhbGVfc2hhcGVfbWFudWFsKG5hbWUgPSAiQ2xpbWF0ZSAoeWVhcikiLAojICAgICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9IGMoIndhcm0gKDIwMDEpIiA9IDE1LCAKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJjb29sICgyMDAxKSIgPSAxNiwgCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiY29sZCAoMjAwMSkiID0gMTcsCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAid2FybSAoMjAxOSkiID0gMCwgCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiY29vbCAoMjAxOSkiID0gMSwgCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiY29sZCAoMjAxOSkiID0gMikpICsKIyAgIGZhY2V0X3dyYXAodmFycyhtaW4pLCBzY2FsZXMgPSAiZnJlZSIpICsKIyAgIHlsYWIoZXhwcmVzc2lvbignQnVsayAtIFJlc3BpcmVkICcqRGVsdGEqJydeMTQqJ0MgKOKAsCknKSkgKwojICAgeGxhYihleHByZXNzaW9uKCdDb25jZW50cmF0aW9uIChnIGtnJ14tMSonKScpKSArCiMgICB0aGVtZV9idygpICsKIyAgIHRoZW1lKHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCkpCmBgYAoKYGBge3IgdHMtc3RhdHN9CiMgZnVuY3Rpb24gZm9yIFR1a2V5IEhTRCB0YWJsZXMKdHVrZXkudGFibGUuZnggPC0gZnVuY3Rpb24oeCwgeWVhciwgdHlwZSwgdmFyKSB7CiAgZGVwdGggPC0gcGFzdGUwKHVuaXF1ZSh4JGx5cl9ib3QpIC0gMTAsICItIiwgdW5pcXVlKHgkbHlyX2JvdCksICIgY20iKQogIGlmICh0eXBlID09ICJpbmMiKSB7CiAgICB4IDwtIHhbeCRkMTRjID4gLTIwMCwgYygiZDE0YyIsIHZhcildCiAgfSAKICByZXR1cm4oCiAgICBUdWtleUhTRChhb3YocmVmb3JtdWxhdGUodmFyLCAiZDE0YyIpLCB4KSlbdmFyXSAlPiUKICAgIGRhdGEuZnJhbWUoLikgJT4lCiAgICBtdXRhdGUoUGFpcnMgPSByb3duYW1lcyguKSkgJT4lCiAgICBtdXRhdGUoYWNyb3NzKHdoZXJlKGlzLm51bWVyaWMpLCByb3VuZCwgMykpICU+JQogICAgZ3QoKSAlPiUKICAgIHRhYl9oZWFkZXIoCiAgICAgIHRpdGxlID0gZGVwdGgsCiAgICAgIHN1YnRpdGxlID0gcGFzdGUoeWVhciwgdHlwZSwgdmFyKQogICAgKSkKfQoKIyMjIDIwMDEKIyMgYnVsawpzcmEuMjAwMS5idWxrLmRmIDwtIGJpbmRfcm93cygKICBsYXBwbHkoc3JhLjE5LjAxLnJlcC5scywgZnVuY3Rpb24obHMpIHsKICAgIGxzIDwtIGxhcHBseShscywgZnVuY3Rpb24oeCkgeFtjb21wbGV0ZS5jYXNlcyh4KV0pCiAgICBkMTRjIDwtIGNhbGNfMTRjKHVubGlzdChscyksIDIwMDEpCiAgICBkZiA8LSBkYXRhLmZyYW1lKGQxNGMgPSBkMTRjLAogICAgICAgICAgICAgICAgICAgICBseXJfYm90ID0gcmVwKGMoMTAsIDIwLCAzMCksIGxlbmd0aChkMTRjKSAvIDMpKQogICAgcmV0dXJuKGRmKQogIH0pLAogIC5pZCA9ICJQTWVjbyIpICU+JQogIG11dGF0ZShQTSA9IHN1YnN0cihQTWVjbywgMSwgMiksCiAgICAgICAgIEVDTyA9IHN1YnN0cihQTWVjbywgMywgNCkpCiMgUE0KIyBsYXBwbHkoc3BsaXQoc3JhLjIwMDEuYnVsay5kZiwgc3JhLjIwMDEuYnVsay5kZiRseXJfYm90KSwgZnVuY3Rpb24oeCkgewojICAgc3VtbWFyeShsbShkMTRjIH4gUE0sIHgpKQojIH0pCmxhcHBseShzcGxpdChzcmEuMjAwMS5idWxrLmRmLCBzcmEuMjAwMS5idWxrLmRmJGx5cl9ib3QpLCBmdW5jdGlvbih4KSB7CiAgdHVrZXkudGFibGUuZngoeCwgIjIwMDEiLCAiYnVsayIsICJQTSIpCn0pCiMgRUNPCiMgbGFwcGx5KHNwbGl0KHNyYS4yMDAxLmJ1bGsuZGYsIHNyYS4yMDAxLmJ1bGsuZGYkbHlyX2JvdCksIGZ1bmN0aW9uKHgpIHsKIyAgIHN1bW1hcnkobG0oZDE0YyB+IEVDTywgeCkpCiMgfSkKbGFwcGx5KHNwbGl0KHNyYS4yMDAxLmJ1bGsuZGYsIHNyYS4yMDAxLmJ1bGsuZGYkbHlyX2JvdCksIGZ1bmN0aW9uKHgpIHsKICB0dWtleS50YWJsZS5meCh4LCAiMjAwMSIsICJidWxrIiwgIkVDTyIpCn0pCgojIyBpbmMKc3JhLjIwMDEuaW5jLmRmMiA8LSBjYmluZChzcmEuMTkuMDEuaW5jLmRmW3JlcCgxOm5yb3coc3JhLjE5LjAxLmluYy5kZiksIDIpLCBjKCJQTSIsICJFQ08iLCAibHlyX2JvdCIpXSwKICAgICAgICAgICAgICAgICAgICAgICAgICBkMTRjID0gYyhzcmEuMTkuMDEuaW5jLmRmJGQxNGNfbWluLCBzcmEuMTkuMDEuaW5jLmRmJGQxNGNfbWF4KSkKc2F2ZShzcmEuMjAwMS5pbmMuZGYyLCBmaWxlID0gInNyYS4yMDAxLmluYy5kZjIuUkRhdGEiKQojIFBNCiMgbGFwcGx5KHNwbGl0KHNyYS4yMDAxLmluYy5kZjIsIHNyYS4yMDAxLmluYy5kZjIkbHlyX2JvdCksIGZ1bmN0aW9uKHgpIHsKIyAgIHN1bW1hcnkobG0oZDE0YyB+IFBNLCB4W3gkZDE0YyA+IC0yMDAsIF0pKQojIH0pCmxhcHBseShzcGxpdChzcmEuMjAwMS5pbmMuZGYyLCBzcmEuMjAwMS5pbmMuZGYyJGx5cl9ib3QpLCBmdW5jdGlvbih4KSB7CiAgdHVrZXkudGFibGUuZngoeCwgIjIwMDEiLCAiaW5jIiwgIlBNIikKfSkKIyBFQ08KIyBsYXBwbHkoc3BsaXQoc3JhLjIwMDEuaW5jLmRmMiwgc3JhLjIwMDEuaW5jLmRmMiRseXJfYm90KSwgZnVuY3Rpb24oeCkgewojICAgc3VtbWFyeShsbShkMTRjIH4gRUNPLCB4W3gkZDE0YyA+IC0yMDAsIF0pKQojIH0pCmxhcHBseShzcGxpdChzcmEuMjAwMS5pbmMuZGYyLCBzcmEuMjAwMS5pbmMuZGYyJGx5cl9ib3QpLCBmdW5jdGlvbih4KSB7CiAgdHVrZXkudGFibGUuZngoeCwgIjIwMDEiLCAiaW5jIiwgIkVDTyIpCn0pCgojIyMgMjAxOQojIyBidWxrCnNyYS4yMDE5LmJ1bGsuZGYgPC0gYmluZF9yb3dzKHNyYS4yMDE5LmxzKQojIFBNCiMgbGFwcGx5KHNwbGl0KHNyYS4yMDE5LmJ1bGsuZGYsIHNyYS4yMDE5LmJ1bGsuZGYkbHlyX2JvdCksIGZ1bmN0aW9uKHgpIHsKIyAgIGlmIChucm93KHgpID09IDI3KSBzdW1tYXJ5KGxtKGQxNGMgfiBQTSwgeFt4JGQxNGMgPiAtMjAwLCBdKSkKIyB9KQpsYXBwbHkoc3BsaXQoc3JhLjIwMTkuYnVsay5kZiwgc3JhLjIwMTkuYnVsay5kZiRseXJfYm90KSwgZnVuY3Rpb24oeCkgewogIGlmIChucm93KHgpID09IDI3KSB0dWtleS50YWJsZS5meCh4LCAiMjAxOSIsICJidWxrIiwgIlBNIikKfSkKIyBFQ08KIyBsYXBwbHkoc3BsaXQoc3JhLjIwMTkuYnVsay5kZiwgc3JhLjIwMTkuYnVsay5kZiRseXJfYm90KSwgZnVuY3Rpb24oeCkgewojICAgaWYgKG5yb3coeCkgPT0gMjcpIHN1bW1hcnkobG0oZDE0YyB+IEVDTywgeFt4JGQxNGMgPiAtMjAwLCBdKSkKIyB9KQpsYXBwbHkoc3BsaXQoc3JhLjIwMTkuYnVsay5kZiwgc3JhLjIwMTkuYnVsay5kZiRseXJfYm90KSwgZnVuY3Rpb24oeCkgewogIGlmIChucm93KHgpID09IDI3KSB0dWtleS50YWJsZS5meCh4LCAiMjAxOSIsICJidWxrIiwgIkVDTyIpCn0pCiMjIGluYwpzcmEuMjAxOS5pbmMuZGYyIDwtIGJpbmRfcm93cyhzcmEuMjAxOS5pbmMubHMpCnNhdmUoc3JhLjIwMTkuaW5jLmRmMiwgZmlsZSA9ICJzcmEuMjAxOS5pbmMuZGYyLlJEYXRhIikKIyBQTQojIGxhcHBseShzcGxpdChzcmEuMjAxOS5pbmMuZGYyLCBzcmEuMjAxOS5pbmMuZGYyJGx5cl9ib3QpLCBmdW5jdGlvbih4KSB7CiMgICBzdW1tYXJ5KGxtKGQxNGMgfiBQTSwgeFt4JGQxNGMgPiAtMjAwLCBdKSkKIyB9KQpsYXBwbHkoc3BsaXQoc3JhLjIwMTkuaW5jLmRmMiwgc3JhLjIwMTkuaW5jLmRmMiRseXJfYm90KSwgZnVuY3Rpb24oeCkgewogIHR1a2V5LnRhYmxlLmZ4KHgsICIyMDE5IiwgImluYyIsICJQTSIpCn0pCiMgRUNPCiMgbGFwcGx5KHNwbGl0KHNyYS4yMDE5LmluYy5kZjIsIHNyYS4yMDE5LmluYy5kZjIkbHlyX2JvdCksIGZ1bmN0aW9uKHgpIHsKIyAgIHN1bW1hcnkobG0oZDE0YyB+IEVDTywgeFt4JGQxNGMgPiAtMjAwLCBdKSkKIyB9KQpsYXBwbHkoc3BsaXQoc3JhLjIwMTkuaW5jLmRmMiwgc3JhLjIwMTkuaW5jLmRmMiRseXJfYm90KSwgZnVuY3Rpb24oeCkgewogIHR1a2V5LnRhYmxlLmZ4KHgsICIyMDE5IiwgImluYyIsICJFQ08iKQp9KQoKIyBjb21wYXJlIDIwMDEgYW5kIDIwMTkKIyBidWxrCnNyYS4wMS4xOS5idWxrLmRmIDwtIGRhdGEuZnJhbWUoCiAgcmJpbmQoc3JhLjIwMDEuYnVsay5kZiwgCiAgICAgICAgc3JhLjIwMTkuYnVsay5kZlssIHdoaWNoKG5hbWVzKHNyYS4yMDE5LmJ1bGsuZGYpICVpbiUgbmFtZXMoc3JhLjIwMDEuYnVsay5kZikpXSksCiAgeWVhciA9IGFzLmZhY3RvcihjKHJlcCgyMDAxLCBucm93KHNyYS4yMDAxLmJ1bGsuZGYpKSwgcmVwKDIwMTksIG5yb3coc3JhLjIwMTkuYnVsay5kZikpKSkpICU+JQogIGZpbHRlcihseXJfYm90IDwgMzEpCnNyYS4wMS4xOS5idWxrLmxzIDwtIHNwbGl0KHNyYS4wMS4xOS5idWxrLmRmLCBzcmEuMDEuMTkuYnVsay5kZiRQTWVjbykKbGFwcGx5KHNyYS4wMS4xOS5idWxrLmxzLCBmdW5jdGlvbihkZikgewogIGxhcHBseShzcGxpdChkZiwgZGYkbHlyX2JvdCksIGZ1bmN0aW9uKHgpIHsKICAgIHR1a2V5LnRhYmxlLmZ4KHgsIHBhc3RlMCh1bmlxdWUoZGYkUE1lY28pLCAiIDIwMDEgdnMuIDIwMTkiKSwgImJ1bGsiLCAieWVhciIpCiAgfSkKfSkKIyBieSBQTQpsYXBwbHkoc3BsaXQoc3JhLjAxLjE5LmJ1bGsuZGYsIHNyYS4wMS4xOS5idWxrLmRmJFBNKSwgZnVuY3Rpb24oZGYpIHsKICBsYXBwbHkoc3BsaXQoZGYsIGRmJGx5cl9ib3QpLCBmdW5jdGlvbih4KSB7CiAgICB0dWtleS50YWJsZS5meCh4LCBwYXN0ZTAodW5pcXVlKGRmJFBNKSwgIiAyMDAxIHZzLiAyMDE5IiksICJidWxrIiwgInllYXIiKQogIH0pCn0pCiMgYnkgRUNPCmxhcHBseShzcGxpdChzcmEuMDEuMTkuYnVsay5kZiwgc3JhLjAxLjE5LmJ1bGsuZGYkRUNPKSwgZnVuY3Rpb24oZGYpIHsKICBsYXBwbHkoc3BsaXQoZGYsIGRmJGx5cl9ib3QpLCBmdW5jdGlvbih4KSB7CiAgICB0dWtleS50YWJsZS5meCh4LCBwYXN0ZTAodW5pcXVlKGRmJEVDTyksICIgMjAwMSB2cy4gMjAxOSIpLCAiYnVsayIsICJ5ZWFyIikKICB9KQp9KQojIGluYwpzcmEuMDEuMTkuaW5jLmRmIDwtIGRhdGEuZnJhbWUoCiAgZDE0YyA9IGMoc3JhLjE5LjAxLmluY1sgLCAiZDE0Y19taW4iXSwKICAgICAgICAgICBzcmEuMTkuMDEuaW5jWyAsICJkMTRjX21heCJdKSwKICBzcmEuMTkuMDEuaW5jWyAsIGMoIlBNZWNvIiwgImx5cl9ib3QiLCAiUE0iLCAiRUNPIiwgInllYXIiKV0pICU+JQogIG11dGF0ZSh5ZWFyID0gYXMuZmFjdG9yKHllYXIpKQpzcmEuMDEuMTkuaW5jLmxzIDwtIHNwbGl0KHNyYS4wMS4xOS5pbmMuZGYsIHNyYS4wMS4xOS5pbmMuZGYkUE1lY28pCmxhcHBseShzcmEuMDEuMTkuaW5jLmxzLCBmdW5jdGlvbihkZikgewogIGxhcHBseShzcGxpdChkZiwgZGYkbHlyX2JvdCksIGZ1bmN0aW9uKHgpIHsKICAgIHR1a2V5LnRhYmxlLmZ4KHgsIHBhc3RlMCh1bmlxdWUoZGYkUE1lY28pLCAiIDIwMDEgdnMuIDIwMTkiKSwgImluYyIsICJ5ZWFyIikKICB9KQp9KQpsYXBwbHkoc3BsaXQoc3JhLjAxLjE5LmluYy5kZiwgc3JhLjAxLjE5LmluYy5kZiRQTSksIGZ1bmN0aW9uKGRmKSB7CiAgbGFwcGx5KHNwbGl0KGRmLCBkZiRseXJfYm90KSwgZnVuY3Rpb24oeCkgewogICAgdHVrZXkudGFibGUuZngoeCwgcGFzdGUwKHVuaXF1ZShkZiRQTSksICIgMjAwMSB2cy4gMjAxOSIpLCAiaW5jIiwgInllYXIiKQogIH0pCn0pCmxhcHBseShzcGxpdChzcmEuMDEuMTkuaW5jLmRmLCBzcmEuMDEuMTkuaW5jLmRmJEVDTyksIGZ1bmN0aW9uKGRmKSB7CiAgbGFwcGx5KHNwbGl0KGRmLCBkZiRseXJfYm90KSwgZnVuY3Rpb24oeCkgewogICAgdHVrZXkudGFibGUuZngoeCwgcGFzdGUwKHVuaXF1ZShkZiRFQ08pLCAiIDIwMDEgdnMuIDIwMTkiKSwgImluYyIsICJ5ZWFyIikKICB9KQp9KQpgYGAKCmBgYHtyIG1pbi0xNGMtc3RhdHN9CnNyYS4wMS4xOS5taW4ucmVwcyA8LSBsZWZ0X2pvaW4oCiAgbWVyZ2Uoc3JhLjAxLjE5LmJ1bGsuZGYsIHNyYS4wMS4xOS5pbmMuZGYsCiAgICAgICAgYnkgPSBjKCJQTWVjbyIsICJQTSIsICJFQ08iLCAieWVhciIsICJseXJfYm90IiksCiAgICAgICAgc3VmZml4ZXMgPSBjKCJfYmxrIiwgIl9pbmMiKSksCiAgcmFzMTguc3AuZGZbICwgYygiQWxfb3giLCAiQWxfcHkiLCAiRmVfZGMiLCAiRmVfb3giLCAiUE0iLCAiRUNPIiwgImx5cl9ib3QiKV0sCiAgYnkgPSBjKCJQTSIsICJFQ08iLCAibHlyX2JvdCIpKSAlPiUKICBtdXRhdGUoWWVhciA9IGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKHllYXIpKSkKCnN1bW1hcnkobG0oZDE0Y19ibGsgfiBBbF9veCArIGx5cl9ib3QgKyB5ZWFyLCBzcmEuMDEuMTkubWluLnJlcHMpKQpzcmEuMDEuMTkubWluLnJlcHMgJT4lCiAgbXV0YXRlKGVjbyA9IGlmZWxzZShFQ08gPT0gInJmIiwgImNvbGQiLCBpZmVsc2UoRUNPID09ICJ3ZiIsICJjb29sIiwgIndhcm0iKSkpICU+JQogIG11dGF0ZShlY29ZZWFyID0gcGFzdGUwKGVjbywgIiAoIiwgeWVhciwgIikiKSkgJT4lCiAgIyBmaWx0ZXIocG1FY29EZXB0aCAhPSAiZ3Jhbml0ZWNvbGQzMCIgJiBwbUVjb0RlcHRoICE9ICJncmFuaXRlY29sZDIwIikgJT4lCiAgZ2dwbG90KC4sIGFlcyhBbF9veCwgZDE0Y19ibGspKSArCiAgZ2VvbV9wb2ludChhZXMoY29sb3IgPSBQTSwgc2hhcGUgPSBlY29ZZWFyKSwgc2l6ZSA9IDMpICsKICBzY2FsZV9jb2xvcl9tYW51YWwobmFtZSA9ICJQYXJlbnQgbWF0ZXJpYWwiLAogICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSBjKCJBTiIgPSBhbmRlc2l0ZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQlMiID0gYmFzYWx0LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJHUiIgPSBncmFuaXRlKSwKICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiQU4iID0gImFuZGVzaXRlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJCUyIgPSAiYmFzYWx0IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJHUiIgPSAiZ3Jhbml0ZSIpKSArIAogIHNjYWxlX3NoYXBlX21hbnVhbChuYW1lID0gIkNsaW1hdGUgKHllYXIpIiwKICAgICAgICAgICAgICAgICAgICAgdmFsdWVzID0gYygid2FybSAoMjAwMSkiID0gMTUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJjb29sICgyMDAxKSIgPSAxNiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImNvbGQgKDIwMDEpIiA9IDE3LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJ3YXJtICgyMDE5KSIgPSAwLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiY29vbCAoMjAxOSkiID0gMSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImNvbGQgKDIwMTkpIiA9IDIpKSArCiAgZmFjZXRfd3JhcCh2YXJzKGx5cl9ib3QpKSArCiAgeWxhYihleHByZXNzaW9uKCdCdWxrICcqRGVsdGEqJydeMTQqJ0MgKOKAsCknKSkgKwogIHhsYWIoZXhwcmVzc2lvbignT3hhbGF0ZSBleHRyYWN0YWJsZSBBbCAoZyBrZydeLTEqJyknKSkgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCkpCmBgYAoKYGBge3IgdHVrZXktcGxvdHN9CiMgY29sb3IgcGFsZXR0ZXMgZm9yIEVDTyAmIFBNCndhcm0gPC0gIiNCRjgxMkQiCmNvb2wgPC0gIiM4MENEQzEiCmNvbGQgPC0gIiMwMTY2NUUiCmdyYW5pdGUgPC0gIiM5ZGFiYTkiCmFuZGVzaXRlIDwtICIjMzgyZGJmIgpiYXNhbHQgPC0gIiNiZjM4MmQiCgojIHBsb3QgZngKYm94cGxvdC5meCA8LSBmdW5jdGlvbihkZiwgdmFyLCB5ZWFyLCB0eXBlLCB0b3Bzb2lsID0gRkFMU0UsIHN1YnNvaWwgPSBGQUxTRSkgewogIGF0bSA8LSBpZmVsc2UoeWVhciA9PSAiMjAwMSIsIGF0bS5kMTQuMjAwMSwgYXRtLmQxNC4yMDE5KQogIGlmICh0eXBlID09ICJpbmMiKSB7CiAgICBkZiA8LSBkZltkZiRkMTRjID4gLTIwMCwgXQogICAgeWxpbSA8LSBjKC02NSwgMTY1KQogIH0gZWxzZSB7CiAgICBpZiAodG9wc29pbCkgewogICAgICBkZiA8LSBkZltkZiRseXJfYm90IDwgMzEsIF0KICAgICAgeWxpbSA8LSBjKC0xMjAsIDE2NSkKICAgICAgfQogICAgaWYgKHN1YnNvaWwpIHsKICAgICAgZGYgPC0gZGZbZGYkbHlyX2JvdCA+IDMxLCBdCiAgICAgIHlsaW0gPC0gYygtMjcwLCA2NSkKICAgIH0KICB9CiAgaWYgKHZhciA9PSAiUE0iKSB7CiAgICBkZiAlPiUKICAgICAgbXV0YXRlKHBtID0gZmFjdG9yKGlmZWxzZShQTSA9PSAiR1IiLCAiZ3Jhbml0ZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKFBNID09ICJBTiIsICJhbmRlc2l0ZSIsICJiYXNhbHQiKSksCiAgICAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSBjKCJncmFuaXRlIiwgImFuZGVzaXRlIiwgImJhc2FsdCIpKSkgJT4lCiAgICAgIGdyb3VwX2J5KHBtLCBseXJfYm90KSAlPiUKICAgICAgZ2dwbG90KC4sIGFlcyhwbSwgZDE0YykpICsKICAgICAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gYXRtLCBsaW5ldHlwZSA9ICJkb3R0ZWQiLCBhbHBoYSA9IDAuMykgKwogICAgICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwKSArCiAgICAgIGdlb21fYm94cGxvdChhZXMoY29sb3IgPSBwbSksIGx3ZCA9IDEpICsKICAgICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoImFuZGVzaXRlIiA9IGFuZGVzaXRlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiYmFzYWx0IiA9IGJhc2FsdCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImdyYW5pdGUiID0gZ3Jhbml0ZSksCiAgICAgICAgICAgICAgICAgICAgICAgICBndWlkZSA9ICJub25lIikgKwogICAgICBzY2FsZV95X2NvbnRpbnVvdXMobGltaXRzID0geWxpbSkgKwogICAgICBmYWNldF9ncmlkKGNvbHMgPSB2YXJzKGx5cl9ib3QpKSArCiAgICAgIHlsYWIoZXhwcmVzc2lvbihEZWx0YSonJ14xNConQyAo4oCwKScpKSArCiAgICAgIGdndGl0bGUocGFzdGUoeWVhciwgdHlwZSkpICsKICAgICAgdGhlbWVfYncoKSArCiAgICAgIHRoZW1lKHBhbmVsLmdyaWQgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgIHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0KSkKICB9IGVsc2UgewogICAgZGYgJT4lCiAgICAgIG11dGF0ZShlY28gPSBmYWN0b3IoaWZlbHNlKEVDTyA9PSAicHAiLCAid2FybSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShFQ08gPT0gIndmIiwgImNvb2wiLCAiY29sZCIpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSBjKCJ3YXJtIiwgImNvb2wiLCAiY29sZCIpKSkgJT4lCiAgICAgIGdyb3VwX2J5KGVjbywgbHlyX2JvdCkgJT4lCiAgICAgIGdncGxvdCguLCBhZXMoZWNvLCBkMTRjKSkgKwogICAgICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSBhdG0sIGxpbmV0eXBlID0gImRvdHRlZCIsIGFscGhhID0gMC4zKSArCiAgICAgIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDApICsKICAgICAgZ2VvbV9ib3hwbG90KGFlcyhjb2xvciA9IGVjbyksIGx3ZCA9IDEpICsKICAgICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoIndhcm0iID0gd2FybSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImNvb2wiID0gY29vbCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImNvbGQiID0gY29sZCksCiAgICAgICAgICAgICAgICAgICAgICAgICBndWlkZSA9ICJub25lIikgKwogICAgICBzY2FsZV95X2NvbnRpbnVvdXMobGltaXRzID0geWxpbSkgKwogICAgICBmYWNldF9ncmlkKGNvbHMgPSB2YXJzKGx5cl9ib3QpKSArCiAgICAgIHlsYWIoZXhwcmVzc2lvbihEZWx0YSonJ14xNConQyAo4oCwKScpKSArCiAgICAgIGdndGl0bGUocGFzdGUoeWVhciwgdHlwZSkpICsKICAgICAgdGhlbWVfYncoKSArCiAgICAgIHRoZW1lKHBhbmVsLmdyaWQgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgIHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0KSkKICB9Cn0KCiMgYnVsawpib3hwbG90LmZ4KHNyYS4yMDAxLmJ1bGsuZGYsICJQTSIsICIyMDAxIiwgImJ1bGsiLCB0b3Bzb2lsID0gVFJVRSkKYm94cGxvdC5meChzcmEuMjAxOS5idWxrLmRmLCAiUE0iLCAiMjAxOSIsICJidWxrIiwgdG9wc29pbCA9IFRSVUUpCmJveHBsb3QuZngoc3JhLjIwMDEuYnVsay5kZiwgIkVDTyIsICIyMDAxIiwgImJ1bGsiLCB0b3Bzb2lsID0gVFJVRSkKYm94cGxvdC5meChzcmEuMjAxOS5idWxrLmRmLCAiRUNPIiwgIjIwMTkiLCAiYnVsayIsIHRvcHNvaWwgPSBUUlVFKQpib3hwbG90LmZ4KHNyYS4yMDE5LmJ1bGsuZGYsICJFQ08iLCAiMjAxOSIsICJidWxrIiwgc3Vic29pbCA9IFRSVUUpCiMgaW5jCmJveHBsb3QuZngoc3JhLjIwMDEuaW5jLmRmMiwgIlBNIiwgIjIwMDEiLCAiaW5jIikKYm94cGxvdC5meChzcmEuMjAxOS5pbmMuZGYyLCAiUE0iLCAiMjAxOSIsICJpbmMiKQpib3hwbG90LmZ4KHNyYS4yMDAxLmluYy5kZjIsICJFQ08iLCAiMjAwMSIsICJpbmMiKQpib3hwbG90LmZ4KHNyYS4yMDE5LmluYy5kZjIsICJFQ08iLCAiMjAxOSIsICJpbmMiKQpgYGAKCmBgYHtyIGRlbHRhLWRlbHRhLXBsb3RzfQojIGRhdGEsIHVuc3VtbWFyaXplZApzcmEudHMuYWxsLnJhdyA8LSByYmluZCgKICBzcmEuMjAwMS5idWxrLmRmWyAsIG5hbWVzKHNyYS4yMDAxLmJ1bGsuZGYpICVpbiUgbmFtZXMoc3JhLjIwMDEuaW5jLmRmMildLAogIHNyYS4yMDE5LmJ1bGsuZGZbICwgbmFtZXMoc3JhLjIwMTkuYnVsay5kZikgJWluJSBuYW1lcyhzcmEuMjAwMS5pbmMuZGYyKV0sCiAgc3JhLjIwMDEuaW5jLmRmMiwKICBzcmEuMjAxOS5pbmMuZGYyWyAsIG5hbWVzKHNyYS4yMDE5LmluYy5kZjIpICVpbiUgbmFtZXMoc3JhLjIwMDEuaW5jLmRmMildKSAlPiUKICBtdXRhdGUoZWNvID0gZmFjdG9yKGlmZWxzZShFQ08gPT0gInBwIiwgIndhcm0iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShFQ08gPT0gIndmIiwgImNvb2wiLCAiY29sZCIpKSwKICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoIndhcm0iLCAiY29vbCIsICJjb2xkIikpLAogICAgICAgICBwbSA9IGZhY3RvcihpZmVsc2UoUE0gPT0gIkdSIiwgImdyYW5pdGUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShQTSA9PSAiQU4iLCAiYW5kZXNpdGUiLCAiYmFzYWx0IikpLAogICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gYygiZ3Jhbml0ZSIsICJhbmRlc2l0ZSIsICJiYXNhbHQiKSksCiAgICAgICAgIFR5cGUgPSBjKHJlcCgiYnVsayIsIGxlbmd0aCA9IG5yb3coc3JhLjIwMDEuYnVsay5kZikpLAogICAgICAgICAgICAgICAgICByZXAoImJ1bGsiLCBsZW5ndGggPSBucm93KHNyYS4yMDE5LmJ1bGsuZGYpKSwKICAgICAgICAgICAgICAgICAgcmVwKCJpbmMiLCBsZW5ndGggPSBucm93KHNyYS4yMDAxLmluYy5kZjIpKSwKICAgICAgICAgICAgICAgICAgcmVwKCJpbmMiLCBsZW5ndGggPSBucm93KHNyYS4yMDE5LmluYy5kZjIpKSksCiAgICAgICAgIHllYXIgPSBjKHJlcCgyMDAxLCBsZW5ndGggPSBucm93KHNyYS4yMDAxLmJ1bGsuZGYpKSwKICAgICAgICAgICAgICAgICAgcmVwKDIwMTksIGxlbmd0aCA9IG5yb3coc3JhLjIwMTkuYnVsay5kZikpLAogICAgICAgICAgICAgICAgICByZXAoMjAwMSwgbGVuZ3RoID0gbnJvdyhzcmEuMjAwMS5pbmMuZGYyKSksCiAgICAgICAgICAgICAgICAgIHJlcCgyMDE5LCBsZW5ndGggPSBucm93KHNyYS4yMDE5LmluYy5kZjIpKSkpCgojIHBsb3QgZngKdHMuZ3JvdXBQbG90LmZ4IDwtIGZ1bmN0aW9uKGRmLCB4LCB5KSB7CiAgcXVvX3ggPC0gc3ltKHgpCiAgcXVvX3kgPC0gc3ltKHkpCiAgaWYgKHggPT0gInBtIikgewogICAgdmFyLm5hbWUgPC0gIlBhcmVudCBtYXRlcmlhbCIKICAgIHZhci52YWx1ZXMgPC0gYygiYW5kZXNpdGUiID0gYW5kZXNpdGUsCiAgICAgICAgICAgICAgICAgICAgImJhc2FsdCIgPSBiYXNhbHQsCiAgICAgICAgICAgICAgICAgICAgImdyYW5pdGUiID0gZ3Jhbml0ZSkgCiAgfSBlbHNlIHsKICAgIHZhci5uYW1lIDwtICJDbGltYXRlIgogICAgdmFyLnZhbHVlcyA8LSAgYygid2FybSIgPSB3YXJtLAogICAgICAgICAgICAgICAgICAgICAiY29vbCIgPSBjb29sLAogICAgICAgICAgICAgICAgICAgICAiY29sZCIgPSBjb2xkKQogIH0KICBwbG90LmRmIDwtIGRmICU+JQogICAgZmlsdGVyKGQxNGMgPiAtMjAwKSAlPiUKICAgIGZpbHRlcihseXJfYm90IDwgMzEpICU+JQogICAgZ3JvdXBfYnkoISEgcXVvX3gsIGx5cl9ib3QsIFR5cGUsIHllYXIpICU+JQogICAgc3VtbWFyaXplKGFjcm9zcyhkMTRjLCBsaXN0KG1lYW4gPSBtZWFuLCBzZCA9IHNkKSkpCiAgaWYgKHkgPT0gImRkMTRjIikgewogICAgcGxvdC5kZiA8LSBwbG90LmRmICU+JQogICAgICBtdXRhdGUoYXRtID0gaWZlbHNlKHllYXIgPT0gMjAwMSwgYXRtLmQxNC4yMDAxLCBhdG0uZDE0LjIwMTkpLAogICAgICAgICAgICAgZGQxNGMgPSBkMTRjX21lYW4gLSBhdG0sCiAgICAgICAgICAgICB1ID0gZDE0Y19tZWFuICsgZDE0Y19zZCAtIGF0bSwKICAgICAgICAgICAgIGwgPSBkMTRjX21lYW4gLSBkMTRjX3NkIC0gYXRtKQogICAgYXRtLmRmIDwtIGF0bS4xNGMKICAgIGF0bS5kZiRkMTRjIDwtIDAKICAgIHlsYWIgPC0gZXhwcmVzc2lvbihEZWx0YSpEZWx0YSonJ14xNConQyAo4oCwKScpIAogICAgfSBlbHNlIHsKICAgICAgcGxvdC5kZiA8LSBwbG90LmRmICU+JQogICAgICAgIG11dGF0ZSh1ID0gZDE0Y19tZWFuICsgZDE0Y19zZCwKICAgICAgICAgICAgICAgbCA9IGQxNGNfbWVhbiAtIGQxNGNfc2QpCiAgICAgIGF0bS5kZiA8LSBhdG0uMTRjCiAgICAgIHlsYWIgPC0gZXhwcmVzc2lvbihEZWx0YSonJ14xNConQyAo4oCwKScpIAogICAgfQogICAgZ2dwbG90KHBsb3QuZGYsIGFlcyh5ZWFyLCAhISBxdW9feSkpICsKICAgIGdlb21fcGF0aChkYXRhID0gYXRtLmRmLCBhZXMoeWVhciwgZDE0YykpICsKICAgIGdlb21fcGF0aChhZXMoY29sb3IgPSAhISBxdW9feCwgbGluZXR5cGUgPSBUeXBlKSwgYWxwaGEgPSAuNSwgbHdkID0gMSkgKwogICAgZ2VvbV9wb2ludChhZXMoY29sb3IgPSAhISBxdW9feCksIAogICAgICAgICAgICAgICBzaXplID0gMywgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDEpKSArCiAgICBnZW9tX2Vycm9yYmFyKAogICAgICBhZXMoeW1pbiA9IGwsCiAgICAgICAgICB5bWF4ID0gdSwKICAgICAgICAgIGNvbG9yID0gISEgcXVvX3gsCiAgICAgICAgICBhbHBoYSA9IFR5cGUpLAogICAgICB3aWR0aCA9IDEsCiAgICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAxKSkgKwogICAgc2NhbGVfY29sb3JfbWFudWFsKG5hbWUgPSB2YXIubmFtZSwKICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSB2YXIudmFsdWVzKSArCiAgICBzY2FsZV9maWxsX21hbnVhbChuYW1lID0gIsKxU0QiLAogICAgICAgICAgICAgICAgICAgICAgdmFsdWVzID0gdmFyLnZhbHVlcykgKwogICAgc2NhbGVfYWxwaGFfbWFudWFsKHZhbHVlcyA9IGMoImJ1bGsiID0gMSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJpbmMiID0gLjUpKSArCiAgICBmYWNldF9ncmlkKGNvbHMgPSB2YXJzKGx5cl9ib3QpKSArCiAgICB5bGFiKHlsYWIpICsKICAgIHhsYWIoIlllYXIiKSArCiAgICB0aGVtZV9idygpICsKICAgIHRoZW1lKHBhbmVsLmdyaWQgPSBlbGVtZW50X2JsYW5rKCkpCn0KIyBwbG90CnRzLmdyb3VwUGxvdC5meChzcmEudHMuYWxsLnJhdywgInBtIiwgImRkMTRjIikKdHMuZ3JvdXBQbG90LmZ4KHNyYS50cy5hbGwucmF3LCAiZWNvIiwgImRkMTRjIikKdHMuZ3JvdXBQbG90LmZ4KHNyYS50cy5hbGwucmF3LCAicG0iLCAiZDE0Y19tZWFuIikKdHMuZ3JvdXBQbG90LmZ4KHNyYS50cy5hbGwucmF3LCAiZWNvIiwgImQxNGNfbWVhbiIpCmBgYAojIyBJbml0aWFsIG1vZGVsaW5nCgpUaGUgZ29hbCBvZiB0aGlzIG1vZGVsaW5nIGV4ZXJjaXNlIGlzIHRvIHNlZSBob3cgcGFyZW50IG1hdGVyaWFsIGFuZCBjbGltYXRlL2Vjb3N5c3RlbSBhZmZlY3QgZXN0aW1hdGVzIG9mIHNvaWwgY2FyYm9uIGFnZXMgYW5kIHRyYW5zaXQgdGltZXMuIEJ1bGsgc29pbCBeMTReQyBvYnNlcnZhdGlvbnMgZnJvbSAyMDAxLCAyMDA5LCBhbmQgMjAxOSB3aWxsIGJlIHVzZWQgdG8gY29uc3RyYWluIHRoZSBjYXJib24gbW9kZWxzLCBhcyB3ZWxsIGFzIG9ic2VydmF0aW9ucyBvZiBeMTReQy1DT34yfiBmcm9tIGxhYm9yYXRvcnkgc29pbCBpbmN1YmF0aW9ucyBvZiBzb2lscyBjb2xsZWN0ZWQgaW4gMjAwMSBhbmQgMjAxOS4gUHJldmlvdXMgd29yayBoYXMgaW5kaWNhdGVkIHRoYXQgdGhlIGNhcmJvbiBzdG9ja3MgYXQgdGhlc2Ugc2l0ZXMgaXMgbGlrZWx5IGF0IGVxdWlsaWJyaXVtLCBzbyB3ZSB3aWxsIGFwcGx5IHRoZSBzdGVhZHktc3RhdGUgYXNzdW1wdGlvbiB0byB0aGUgbW9kZWxpbmcuCgojIyMgVHdvLXBvb2wgbW9kZWxzCgpPbmUgcG9vbCBtb2RlbHMgaGF2ZSBiZWVuIHNob3duIHJlcGVhdGVkbHkgdG8gYmUgaW5hZGVxdWF0ZSBmb3IgZGVzY3JpYmluZyBzb2lsIGNhcmJvbiBkeW5hbWljcy4gSG93ZXZlciwgYXMgc2ltcGxlIG1vZGVscyBhcmUgZWFzaWVyIHRvIGNvbnN0cmFpbiwgd2Ugd2lsbCBzdGFydCB3aXRoIGEgdHdvLXBvb2wgcGFyYWxsZWwgYW5kIHR3by1zZXJpZXMgbW9kZWxzLCBhcyB0aGVzZSBhcmUgdGhlIHNpbXBsZXN0IG1vZGVsIHN5c3RlbSBiZXlvbmQgdGhlIHNpbmdsZSBwb29sIGFwcHJvYWNoLiAKClRoZSB0d28tcG9vbCBwYXJhbGxlbCBtb2RlbCByZXF1aXJlcyB0aGUgZm9sbG93aW5nIHBhcmFtZXRlcnM6CiogZGVjb21wb3NpdGlvbiBjb25zdGFudHMgZm9yIGVhY2ggcG9vbCAoKmsqfjF+LCAqayp+Mn4pCiogaW5wdXQgcGFydGl0aW9uaW5nIGNvZWZmaWNpZW50ICgkXGdhbW1hJCkKKiBzdGVhZHktc3RhdGUgY2FyYm9uIHN0b2NrcyAoQykKKiBpbnB1dHMgKEkpCiogaW5pdGlhbCB2YWx1ZXMgb2YgXjE0XkMKMQpUaGUgdHdvLXBvb2wgc2VyaWVzIG1vZGVsIHJlcXVpcmVzIHRoZSBmb2xsb3dpbmcgcGFyYW1ldGVyczoKKiBkZWNvbXBvc2l0aW9uIGNvbnN0YW50cyBmb3IgZWFjaCBwb29sICgqayp+MX4sICprKn4yfikKKiB0cmFuc2ZlciBjb2VmZmljaWVudCAoJFxhbHBoYSQpCiogc3RlYWR5LXN0YXRlIGNhcmJvbiBzdG9ja3MgKEMpCiogaW5wdXRzIChJKQoqIGluaXRpYWwgdmFsdWVzIG9mIF4xNF5DCgpEZWNvbXBvc2l0aW9uIHJhdGVzICgqayopIGFyZSByZWxhdGVkIHRvIHRoZSBhbW91bnQgb2YgXjE0XkMgaW4gYSBwcmUtYm9tYiBzeXN0ZW0gKGZyYWN0aW9uIG1vZGVybiwgKkYqKSBhdCBzdGVhZHktc3RhdGUgYnkgdGhlIGZvbGxvd2luZyBlcXVhdGlvbnMgKGNmLiBTY2h1dXIsIERydWZmbGUsIGFuZCBUcnVtYm9yZSwgMjAxNik6Cj4qKkVxLiAxKioKCiQkRiA9IFxmcmFje2t9e2sgKyBcbGFtYmRhfSQkCj4qKkVxLiAyKioKCiQkayA9IFxmcmFje1xsYW1iZGEgXGNkb3QgRn17MSAtIEZ9JCQKPndoZXJlICRcbGFtYmRhJCBpcyB0aGUgcmFkaW9hY3RpdmUgZGVjYXkgY29uc3RhbnQgKDEvODI2NykuCgpBcyB0aGUgZGVjb21wb3NpdGlvbiByYXRlcyB3aWxsIHZhcnksIHRoZSBpbml0aWFsIF4xNF5DIGNvbnRlbnQgY2FuIGJlIGRldGVybWluZWQgZHluYW1pY2FsbHkgd2l0aCBlcXVhdGlvbiAxLgoKQ2FyYm9uIHN0b2NrcyBhcmUga25vd24sIHdoaWxlIGlucHV0cyB3aWxsIGJlIGVzdGltYXRlZCBhbmQgYXJlIHJlbGF0ZWQgdG8gdGhlIHN0ZWFkeS1zdGF0ZSBjb25kaXRpb25zIGJ5IHRoZSBmb2xsb3dpbmcgZXF1YXRpb246IAo+KipFcS4gMyoqCgokJEkgPSAoa197MX0gXGNkb3QgQ197MX0pICsgKGtfezJ9IFxjZG90IENfezJ9KSQkCj53aGVyZSAqQ34xfiogYW5kICpDfjJ+KiBhcmUgdGhlIGNhcmJvbiBzdG9ja3Mgb2YgdGhlIHR3byBtb2RlbCBwb29scy4KCkJvdGggc3RvY2tzIGFuZCBpbnB1dHMgY2FuIGJlIHNjYWxlZCB0byB0aGUga25vd24gdmFsdWUgb2YgdGhlIHRvdGFsIGNhcmJvbiBwb29sIG9uY2UgdGhlIHN0ZWFkeS1zdGF0ZSBwYXJhbWV0ZXJzICgqa34xfiosICprfjJ+KiwgYW5kICRcZ2FtbWEkIG9yICRcYWxwaGEkKSBoYXZlIGJlZW4gZGV0ZXJtaW5lZC4gUG9vbCBzaXplcyBhcmUgYSBmdW5jdGlvbiBvZiB0aGUgaW5wdXRzIGFuZCBpbnB1dCBwYXJ0aXRpb25pbmcgY29lZmZpY2llbnQgYXQgc3RlYWR5LXN0YXRlLgoKQSBNb250ZS1DYXJsbyBNYXJrb3YgY2hhaW4gYXBwcm9hY2ggd2lsbCBiZSB1c2VkIGZvciBwYXJhbWV0ZXIgZXN0aW1hdGlvbiBpbiBjb21iaW5hdGlvbiB3aXRoIGFuIGluaXRpYWwgb3B0aW1pemF0aW9uIGFsZ29yaXRobSB0byBkZXRlcm1pbmUgdGhlIGJlc3Qgc2V0IG9mIGluaXRpYWwgcGFyYW1ldGVycy4KCiMjIFdvcmtmbG93CgpJbml0aWFsIG1vZGVsIGZpdHRpbmcgd2FzIHBlcmZvcm1lZCBmb3IgYm90aCBtb2RlbCBzdHJ1Y3R1cmVzIHVzaW5nIGdlbmVyb3VzIHBhcmFtZXRlciByYW5nZXMgWzAsIDFdIGZvciBhbGwgdGhyZWUgcGFyYW1ldGVycyAoKmt+MX4qLCAqa34yfiosICRcZ2FtbWEkIG9yICRcYWxwaGEkKS4gVGhlIGluaXRpYWwgcGFyYW1ldGVyIHNldCB3YXMgZm91bmQgYnkgZml0dGluZyB0aGUgbW9kZWxzIGJ5IGV5ZSwgZm9sbG93ZWQgYnkgb3B0aW1pemF0aW9uIHdpdGggdGhlIGZ1bmN0aW9uICJtb2RGaXQiIChSIHBhY2thZ2UgRk1FKSwgdXNpbmcgdGhlIE5lbGRlci1NZWFkIGFsZ29yaXRobS4gVGhlIGJlc3Qgc2V0IG9mIHBhcmFtZXRlcnMgZm91bmQgYnkgbW9kRml0IHdhcyB0aGVuIHVzZWQgYXMgdGhlIGlucHV0IHRvIGEgTW9udGUgQ2FybG8gTWFya292IENoYWluIChNQ01DKSwgdXNpbmcgdGhlIGZ1bmN0aW9uICJtb2RNQ01DIiAoUiBwYWNrYWdlIEZNRSkuIFRoZSBudW1iZXIgb2YgaXRlcmF0aW9ucyBmb3IgdGhlIE1DTUMgb3B0aW1pemF0aW9uIHdhcyBzZXQgYXQgNTAwMCBpbnRpYWxseSwgd2l0aCBkZWxheWVkIHJlamVjdGlvbiBlbXBsb3llZCB0byBpbmNyZWFzZSBlZmZpY2llbmN5LiAKClRoZSBzdW0gb2YgdGhlIG1lYW4gc3F1YXJlZCBlcnJvciBmb3IgdGhlIGJlc3QgcGFyYW1ldGVyIHNldCB3YXMgc2xpZ2h0bHkgbG93ZXIgZm9yIHRoZSBwYXJhbGxlbCBzdHJ1Y3R1cmUgdGhhbiBmb3IgdGhlIHNlcmllcyBzdHJ1Y3R1cmUuIEFkZGl0aW9uYWxseSwgdGhlIG92ZXJhbGwgbWVhbiBlcnJvciBvZiB0aGUgcmVzaWR1YWxzIHdhcyBhbHNvIGxvd2VyIGZvciB0aGUgcGFyYWxsZWwgc3RydWN0dXJlLCBtb2RlcmF0ZWx5IHNvIGZvciB0aGUgYnVsayBDIG9ic2VydmF0aW9ucyBidXQgc3Vic3RhbnRpYWxseSBzbyBmb3IgdGhlIHJlc3BpcmF0aW9uIG9ic2VydmF0aW9ucyAoaW4gYW5kZXNpdGUgYW5kIGdyYW5pdGUgc29pbHMgaW4gcGFydGljdWxhcikuCgpIb3dldmVyLCB0aGVzZSBpbml0aWFsIGZpdHMgeWllbGRlZCB1bnJlYWxpc3RpYyBwYXJhbWV0ZXIgZXN0aW1hdGVzIGZvciBtdWx0aXBsZSBzaXRlcywgcGFydGljdWxhcmx5IGF0IHRoZSBsb3dlciBkZXB0aHMuIEFkZGl0aW9uYWxseSwgdGhlIG1vZEZpdCBvdXRwdXQgc2hvd2VkIHZlcnkgaGlnaCBjb3JyZWxhdGlvbiBiZXR3ZWVuIHRoZSBwYXJhbWV0ZXJzIGZvciBib3RoIG1vZGVsIHN0cnVjdHVyZXMgKHNsaWdodGx5IGhpZ2hlciBmb3IgdGhlIHR3by1wb29sIHNlcmllcyBtb2RlbCkuIAoKYGBge3IgbW9kLXV0aWxzfQojIGsgZnJvbSBmcmFjdGlvbiBtb2Rlcm4KayA8LSBmdW5jdGlvbiAoRm0pIHsKICAoRm0gKiBsYW1iZGEpLygxIC0gRm0pCn0KCiMgZDE0QyBmcm9tIGZyYWN0aW9uIG1vZGVybiAKZm1fMTRjIDwtIGZ1bmN0aW9uIChmbSwgZGF0ZSkgewogIChmbSAqIGV4cChsYW1iZGEgKiAoMTk1MCAtIGRhdGUpKSAtIDEpICogMTAwMAp9CgojIHByZS1ib21iIGZyYWN0aW9uIG1vZGVybiBmcm9tIGsgKHN0ZWFkeS1zdGF0ZSBhc3N1bWVkKQpmbSA8LSBmdW5jdGlvbiAoayl7CiAgay8oayArIGxhbWJkYSkKfQpgYGAKCmBgYHtyIG1vZC1jb25zdHJhaW50cywgaW5jbHVkZSA9IEZBTFNFfQojIEluZGljZXMgZm9yIGVhY2ggZGVwdGggaW5jcmVtZW50Cml4LjEwIDwtIHNlcSgxLCAyNywgMykKaXguMjAgPC0gc2VxKDIsIDI3LCAzKQppeC4zMCA8LSBzZXEoMywgMjcsIDMpCgojIyBTT0Mgc3RvY2tzCiMgdXNlIDIwMTkgU09DIHN0b2NrcyBmb3Igc3RlYWR5LXN0YXRlIGVzdGltYXRlcwpjc29jLjE5LjBfMzAuZGYgPC0gYmluZF9yb3dzKAogIGxhcHBseShzcmEuMjAxOS5zcC5scywgZnVuY3Rpb24oZGYpIHsKICAgIGRmIDwtIHN1cHByZXNzTWVzc2FnZXMoCiAgICAgIGRmICU+JQogICAgICAgIGZpbHRlcihseXJfYm90IDwgMzEgJiBseXJfYm90ID4gMCkgJT4lCiAgICAgICAgc2VsZWN0KFBNZWNvLCBseXJfdG9wLCBseXJfYm90LCBseXJfc29jKSAlPiUKICAgICAgICBncm91cF9ieShQTWVjbywgbHlyX3RvcCwgbHlyX2JvdCkpCiAgICByZXR1cm4oZGF0YS5mcmFtZShkZikpCiAgfSkKKQojIHdyaXRlLmNzdihjc29jLjE5LjBfMzAuZGYsICJjc29jLjE5LjBfMzAuY3N2IikKCiMgY29udmVydCB0byAyNyBlbGVtZW50IGxpc3QKY3NvYy4xOS4wXzMwLmxzIDwtIHNwbGl0KGNzb2MuMTkuMF8zMC5kZiwgcGFzdGUwKGNzb2MuMTkuMF8zMC5kZiRQTWVjbywgIl8iLCBjc29jLjE5LjBfMzAuZGYkbHlyX3RvcCwgIi0iLCBjc29jLjE5LjBfMzAuZGYkbHlyX2JvdCkpCgojIGF2ZXJhZ2UKY3NvYy4xOS4wXzMwIDwtIGxhcHBseShjc29jLjE5LjBfMzAubHMsIGZ1bmN0aW9uKGRmKSB7CiAgZGF0YS5mcmFtZSgKICAgIGRmICU+JQogICAgICBncm91cF9ieShQTWVjbywgbHlyX3RvcCwgbHlyX2JvdCkgJT4lCiAgICAgIHN1bW1hcml6ZShseXJfc29jID0gbWVhbihseXJfc29jKSkpCn0pCgojIG1ha2UgaW50byBvYnMgZGF0YSBmcmFtZSBmb3IgbW9kLmNvc3QgZngKb2JzLmNTdG9jayA8LSBsYXBwbHkoY3NvYy4xOS4wXzMwLmxzLCBmdW5jdGlvbihkZikgewogIHJldHVybihkYXRhLmZyYW1lKHRpbWUgPSByZXAoYygyMDAxLjUsIDIwMDkuNSwgMjAxOS41KSwgZWFjaCA9IDMpLCBjU3RvY2sgPSByZXAoZGYkbHlyX3NvYywgMykpKQp9KQoKIyMgSW5wdXRzCiMgaW5pdGlhbCBpbnB1dHMgd2lsbCBiZSBzZXQgYXQgNCUgb2YgdGhlIGxheWVyIGNhcmJvbiBzdG9ja3MgKGFyYml0cmFyeSkKaW4uaSA8LSBsYXBwbHkoY3NvYy4xOS4wXzMwLCBmdW5jdGlvbih4KSAuMDQgKiB4JGx5cl9zb2MpCiMgSW5wdXRzIHdpbGwgYmUgYWRqdXN0ZWQgYmFzZWQgb24gdGhlIGZpdHRlZCBwYXJhbWV0ZXJzIHRvIG1hdGNoIG1lYXN1cmVkIHN0b2NrcyBsYXRlcgoKIyMgMTRDIGNvbnN0cmFpbnRzCiMgYnVsawpvYnMuYnVsay4xNGMgPC0gdW5saXN0KAogIGxhcHBseShzZXFfYWxvbmcoc3JhLjE5LjAxLnJlcC5scyksIGZ1bmN0aW9uKGkpIHsKICAjIGluZGV4IGFsb25nIGRlcHRoIGludGVydmFscyAwLTEwLCAxMC0yMCwgMjAtMzAKICBkZXB0aC5scyA8LSBsYXBwbHkoc2VxX2Fsb25nKDE6MyksIGZ1bmN0aW9uKGopIHsKICAgIGModW5saXN0KGxhcHBseShzcmEuMTkuMDEucmVwLmxzW1tpXV0sICJbWyIsIGopKSwKICAgICAgc3BsaXQoc3BsaXQoc3JhLjE5LjAxLjA5LCBzcmEuMTkuMDEuMDkkUE1lY28pW1tpXV0sCiAgICAgICAgICAgIHNwbGl0KHNyYS4xOS4wMS4wOSwgc3JhLjE5LjAxLjA5JFBNZWNvKVtbaV1dWyJseXJfYm90Il0pW1tqXV1bICwgImZtIl1bMl0sCiAgICAgIHVubGlzdChzcGxpdChzcmEuMjAxOS5sc1tbaV1dLCBzcmEuMjAxOS5sc1tbaV1dWyJseXJfYm90Il0pW1tqXV1bImZtIl0pKQogIH0pCiAgcmVwczAxIDwtIGxlbmd0aChzcmEuMTkuMDEucmVwLmxzW1tpXV0pCiAgZGVwdGguZGZzIDwtIGxhcHBseShkZXB0aC5scywgZnVuY3Rpb24oZm0pIHsKICAgIGRhdGEuZnJhbWUodGltZSA9IGMocmVwKDIwMDEuNSwgcmVwczAxKSwgMjAwOS41LCByZXAoMjAxOS41LCAzKSksCiAgICAgICAgICAgICAgIGJ1bGtDID0gRGVsdGExNENfZnJvbV9BYnNvbHV0ZUZyYWN0aW9uTW9kZXJuKGZtKSkKICB9KQogIHJldHVybihkZXB0aC5kZnMpCn0pLCByZWN1cnNpdmUgPSBGQUxTRSkKbmFtZXMob2JzLmJ1bGsuMTRjKSA8LSBwYXN0ZTAocmVwKGMoIkFOIiwgIkJTIiwgIkdSIiksIGVhY2ggPSA5KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVwKGMoInBwIiwgInJmIiwgIndmIiksIGVhY2ggPSAzLCB0aW1lcyA9IDMpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXAoYygiXzAtMTAiLCAiXzEwLTIwIiwgIl8yMC0zMCIpLCB0aW1lcyA9IDkpKQpzYXZlKG9icy5idWxrLjE0YywgZmlsZSA9ICJvYnMuYnVsay4xNGMuUkRhdGEiKQoKIyByZXNwaXJhdGlvbgpzcmEuMTkuMDEuaW5jLm1pbi5tYXggPC0gdW5saXN0KAogIGxhcHBseShzZXFfYWxvbmcoMTozKSwgZnVuY3Rpb24oaSkgewogICAgbGFwcGx5KAogICAgICBtYXBwbHkobWVyZ2UsCiAgICAgICAgICAgICBsYXBwbHkobGFwcGx5KHNyYS4xOS4wMS5pbmMubHMsICJbWyIsIDIpLCAiW1siLCBpKSwgCiAgICAgICAgICAgICBsYXBwbHkobGFwcGx5KHNyYS4xOS4wMS5pbmMubHMsICJbWyIsIDMpLCAiW1siLCBpKSwKICAgICAgICAgICAgIFNJTVBMSUZZID0gRkFMU0UpLAogICAgICBmdW5jdGlvbihkZikgewogICAgICAgIGRhdGEuZnJhbWUodGltZSA9IDIwMDEuNSwgcmVzcCA9IGMoZGYkeCwgZGYkeSkpCiAgICAgIH0pCiAgfSksIHJlY3Vyc2l2ZSA9IEZBTFNFKQpuYW1lcyhzcmEuMTkuMDEuaW5jLm1pbi5tYXgpIDwtIHBhc3RlMChuYW1lcyhzcmEuMTkuMDEuaW5jLm1pbi5tYXgpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVwKGMoIl8wLTEwIiwgIl8xMC0yMCIsICJfMjAtMzAiKSwgZWFjaCA9IDkpKQpzcmEuMTkuMDEuaW5jLm1pbi5tYXggPC0gbGFwcGx5KHNyYS4xOS4wMS5pbmMubWluLm1heCwgZnVuY3Rpb24oZGYpIHsKICBkZiRyZXNwIDwtIGNhbGNfMTRjKGRmJHJlc3AsIDIwMDEpCiAgcmV0dXJuKGRmKQp9KQoKc3JhLjIwMTkuaW5jLm1pbi5tYXggPC0gdW5saXN0KGxhcHBseShzcmEuMjAxOS5pbmMubHMsIGZ1bmN0aW9uKGRmKSB7CiAgbGFwcGx5KHNwbGl0KGRmLCBkZiRseXJfYm90KSwgZnVuY3Rpb24oeCkgewogICAgeCRyZXNwIDwtIHgkZDE0YwogICAgeCR0aW1lIDwtIHgkWWVhciArIC41CiAgICByZXR1cm4oeFsgLCBjKCJ0aW1lIiwgInJlc3AiKV0pCiAgfSkKfSksIHJlY3Vyc2l2ZSA9IEZBTFNFKQpuYW1lcyhzcmEuMjAxOS5pbmMubWluLm1heCkgPC0gZ3N1YigiXFwuIiwgIl8iLCBuYW1lcyhzcmEuMjAxOS5pbmMubWluLm1heCkpCmZvciAoaSBpbiBzZXFfYWxvbmcobmFtZXMoc3JhLjIwMTkuaW5jLm1pbi5tYXgpKSkgewogIG5hbWVzKHNyYS4yMDE5LmluYy5taW4ubWF4KVtpXSA8LSBpZmVsc2UoZ3JlcGwoIjEwIiwgbmFtZXMoc3JhLjIwMTkuaW5jLm1pbi5tYXgpW2ldKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnc3ViKCIxMCIsICIwLTEwIiwgbmFtZXMoc3JhLjIwMTkuaW5jLm1pbi5tYXgpW2ldKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZ3JlcGwoIjIwIiwgbmFtZXMoc3JhLjIwMTkuaW5jLm1pbi5tYXgpW2ldKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3N1YigiMjAiLCAiMTAtMjAiLCBuYW1lcyhzcmEuMjAxOS5pbmMubWluLm1heClbaV0pLCBnc3ViKCIzMCIsICIyMC0zMCIsIG5hbWVzKHNyYS4yMDE5LmluYy5taW4ubWF4KVtpXSkpKQp9CgpvYnMucmVzcC4xNGMgPC0gcmJpbmQoYmluZF9yb3dzKHNyYS4xOS4wMS5pbmMubWluLm1heCwgLmlkID0gImlkIiksCiAgICAgICAgICAgICAgICAgICAgICBiaW5kX3Jvd3Moc3JhLjIwMTkuaW5jLm1pbi5tYXgsIC5pZCA9ICJpZCIpKQpvYnMucmVzcC4xNGMgPC0gbGFwcGx5KHNwbGl0KG9icy5yZXNwLjE0Yywgb2JzLnJlc3AuMTRjJGlkKSwgZnVuY3Rpb24oZGYpIGRmWyAsIDI6M10pCgpzYXZlKG9icy5yZXNwLjE0YywgZmlsZSA9ICJvYnMucmVzcC4xNGMuUkRhdGEiKQoKIyMgaW5wdXQvc3RvY2sgcmF0aW8KcmFzMDYgPC0gZGF0YS5mcmFtZShyZWFkX2V4Y2VsKCIuLi9kYXRhL2V4dGVybmFsL3NyYV9yYXNfaW5jL1Jlc3BSYXRlc19SYXNtdXNzZW4yMDA2Lnhsc3giLCBzaGVldCA9ICJSYXRlc1N1bSIpKQojIE9icyBjb3N0Cm9icy5mbHguc3RvY2sgPC0gbGFwcGx5KHNwbGl0KHJhczA2LCByYXMwNiRQTWVjbyksIGZ1bmN0aW9uKHgpIHsKICBkYXRhLmZyYW1lKHRpbWUgPSAyMDAxLjUsICMgYXJiaXRyYXJ5CiAgICAgICAgICAgICBmbHguc3RvY2sgPSB4WyAsICJmbHhfc3RvY2tfcmF0aW8iXSkKfSkKCiMgY2FsY3VsYXRlIGlucHV0cyB1c2luZyBmbHgvc3RvY2sgcmF0aW8KaW4uZmx4LnN0b2NrIDwtIGxhcHBseShzZXFfYWxvbmcob2JzLmZseC5zdG9jayksIGZ1bmN0aW9uKGkpIHsKICBvYnMuZmx4LnN0b2NrW1tpXV1bWyJmbHguc3RvY2siXV0vY3NvYy4xOS4wXzMwW2l4LjEwXVtbaV1dW1sibHlyX3NvYyJdXQp9KQoKIyBGbHV4IGVzdGltYXRlZCBmcm9tIEdvdWxkZW4gZXQgYWwuIDIwMTI7IFRhbmcgZXQgYWwuIDIwMDU7IFdhbmcgZXQgYWwuIDIwMDA7IEdhdWRpbnNraSAyMDAwCiMgZmx1eGVzIGJ5IGVsZXZhdGlvbiBmcm9tIEdQUCByZXBvcnRlZCBpbiBHb3VsZGVuIGV0IGFsLiBGaWcuIDUgYW5kIGFwcHJveGltYXRlZAojIFJoIHBlcmNlbnRhZ2UgZnJvbSBUYW5nIGV0IGFsLiAyMDA1ID0gMC40NCAoYW5uLiBtZWFuIEJsb2RnZXR0KTsgY2YuIDAuNDggSGFydmFyZCBGb3Jlc3QKIyBBIGhvcml6b24gZXN0LiAwLjU1IGZyb20gR2F1ZGluc2tpCiMgYXNzdW1pbmcgQSA9IDAtMzAsIGFzc3VtZSAwLTEwID0gNTAlLCAxMC0yMCA9IDMwJSwgMjAtMzAgPSAyMCUgb2YgdG90YWwgQSBwcm9kdWN0aW9uIApoem5BLlJoLmtnbTIgPC0gMC40NCAqIDAuNTUgKiAxMF4tMwpncHAubHMgPC0gYygxODAwLCAxNjAwLCAxNDAwKQppbi5mcmMubHMgPC0gYygwLjUsIDAuMywgMC4yKQoKIyBmeCBmb3IgY2FsY3VsYXRpbmcgaW5wdXRzCmluLmZseC5meCA8LSBmdW5jdGlvbihQTWVjb19kZXB0aCkgewogIGdwcCA8LSBpZmVsc2UoZ3JlcGwoInBwIiwgUE1lY29fZGVwdGgpLCBncHAubHNbMV0sIGlmZWxzZShncmVwbCgid2YiLCBQTWVjb19kZXB0aCksIGdwcC5sc1syXSwgZ3BwLmxzWzNdKSkKICBpbi5mcmMgPC0gaWZlbHNlKGdyZXBsKCIwLTEwIiwgUE1lY29fZGVwdGgpLCBpbi5mcmMubHNbMV0sIGlmZWxzZShncmVwbCgiMTAtMjAiLCBQTWVjb19kZXB0aCksIGluLmZyYy5sc1syXSwgaW4uZnJjLmxzWzNdKSkKICByZXR1cm4oZ3BwICogaW4uZnJjICogaHpuQS5SaC5rZ20yKQp9CgojIGlucHV0IGxpc3QKaW4uZXN0IDwtIGxhcHBseShzZXFfYWxvbmcob2JzLmNTdG9jayksIGZ1bmN0aW9uKGkpIHsKICBQTWVjb19kZXB0aCA8LSBuYW1lcyhvYnMuY1N0b2NrKVtpXQogIHJldHVybihpbi5mbHguZngoUE1lY29fZGVwdGgpKQp9KQpuYW1lcyhpbi5lc3QpIDwtIG5hbWVzKG9icy5jU3RvY2spCmBgYAoKYGBge3IgbW9kLWZ1bnMtZ2VufQojIGluZGV4IG9mIHllYXJzIGZvciB3aGljaCBidWxrL3Jlc3AgMTRDIGFyZSBrbm93bgp5ZWFyLml4IDwtIGMod2hpY2goRGF0bSREYXRlID09IDIwMDEuNSksCiAgICAgICAgICAgICB3aGljaChEYXRtJERhdGUgPT0gMjAwOS41KSwKICAgICAgICAgICAgIHdoaWNoKERhdG0kRGF0ZSA9PSAyMDE5LjUpKQoKIyBmdW5jdGlvbiBmb3Igc2F2aW5nIGNvbnN0cmFpbnQgZGF0YSBpbiBhIGRhdGFmcmFtZSBmb3IgcGxvdHRpbmcgaW4gZ2dwbG90Jwpjb24uZGYuZnggPC0gZnVuY3Rpb24oUE1lY29fZGVwdGgpIHsKICBidWxrLmRmIDwtIG9icy5idWxrLjE0Y1tbUE1lY29fZGVwdGhdXQogIHJlc3AuZGYgPC0gb2JzLnJlc3AuMTRjW1tQTWVjb19kZXB0aF1dCiAgcmV0dXJuKAogICAgY29uLmRmIDwtIGRhdGEuZnJhbWUocG9vbCA9IGMocmVwKCJidWxrIEMiLCBucm93KGJ1bGsuZGYpKSwgcmVwKCJyZXNwaXJhdGlvbiIsIG5yb3cocmVzcC5kZikpKSwKICAgICAgICAgICAgICAgICAgICAgICAgIGQxNGMgPSBjKGJ1bGsuZGYkYnVsa0MsIHJlc3AuZGYkcmVzcCksCiAgICAgICAgICAgICAgICAgICAgICAgICBZZWFyID0gYyhidWxrLmRmJHRpbWUsIHJlc3AuZGYkdGltZSkpKQp9CgojIHBsb3QgZnVuY3Rpb24KQzE0LjJwLnBsb3QuZnggPC0gZnVuY3Rpb24ocGxvdC5kZiwgY29uLmRmLCBtb2QsIFBNZWNvX2RlcHRoKSB7CiAgcGxvdC5kZiAlPiUKICBmaWx0ZXIocG9vbCA9PSAiYnVsayBDIiB8IHBvb2wgPT0gInJlc3BpcmF0aW9uIiB8IHBvb2wgPT0gImF0bSIpICU+JQogIGdncGxvdCguLCBhZXMoeWVhcnMsIGQxNEMsIGNvbG9yID0gcG9vbCkpICsKICBnZW9tX3BhdGgoKSArCiAgZ2VvbV9wb2ludChkYXRhID0gY29uLmRmLCBhZXMoWWVhciwgZDE0YywgY29sb3IgPSBwb29sKSwgc2l6ZSA9IDMpICsKICBzY2FsZV9jb2xvcl9tYW51YWwoCiAgICBuYW1lID0gIlBvb2wiLAogICAgdmFsdWVzID0gYygiYXRtIiA9IDgsCiAgICAgICAgICAgICAgICJidWxrIEMiID0gImJsYWNrIiwKICAgICAgICAgICAgICAgImZhc3QiID0gIiNEODFCNjAiLAogICAgICAgICAgICAgICAic2xvdyIgPSAiIzFFODhFNSIsCiAgICAgICAgICAgICAgICJyZXNwaXJhdGlvbiIgPSAiI0ZGQzEwNyIpKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGxpbWl0cyA9IGMoMTk1MCwgMjAyMikpICsKICBnZ3RpdGxlKHBhc3RlKFBNZWNvX2RlcHRoLCBtb2QpKSArCiAgeGxhYigiWWVhciIpICsKICB5bGFiKGV4cHJlc3Npb24oJycqRGVsdGEqJydeMTQqJ0MgKOKAsCknKSkgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKHBhbmVsLmdyaWQgPSBlbGVtZW50X2JsYW5rKCkpCn0KQzE0LjFwLnBsb3QuZnggPC0gZnVuY3Rpb24ocGxvdC5kZiwgY29uLmRmLCBtb2QsIFBNZWNvX2RlcHRoKSB7CiAgZ2dwbG90KHBsb3QuZGYsIGFlcyh5ZWFycywgZDE0QywgY29sb3IgPSBwb29sKSkgKwogIGdlb21fcGF0aCgpICsKICBnZW9tX3BvaW50KGRhdGEgPSBjb24uZGYsIGFlcyhZZWFyLCBkMTRjLCBjb2xvciA9IHBvb2wpLCBzaXplID0gMykgKwogIHNjYWxlX2NvbG9yX21hbnVhbCgKICAgIG5hbWUgPSAiUG9vbCIsCiAgICB2YWx1ZXMgPSBjKCJhdG0iID0gOCwKICAgICAgICAgICAgICAgImJ1bGsgQyIgPSAiYmxhY2siLAogICAgICAgICAgICAgICAicmVzcGlyYXRpb24iID0gIiNGRkMxMDciKSkgKwogIHNjYWxlX3hfY29udGludW91cyhsaW1pdHMgPSBjKDE5NTAsIDIwMjIpKSArCiAgZ2d0aXRsZShwYXN0ZShQTWVjb19kZXB0aCwgIiAxcCBidWxrICsgMXAgcmVzcCIpKSArCiAgeGxhYigiWWVhciIpICsKICB5bGFiKGV4cHJlc3Npb24oJycqRGVsdGEqJydeMTQqJ0MgKOKAsCknKSkgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKHBhbmVsLmdyaWQgPSBlbGVtZW50X2JsYW5rKCkpCn0KCiMgc2V0IHVwIG1vZGVsIGZ1bmN0aW9uIGZvciBvcHRpbWl6YXRpb24KIyBOT1RFOiBwYXJbM10gZm9yIDJwcyBtb2RlbCBjaGFuZ2VkIHRvIHByb3BvcnRpb24gdHJhbnNmZXJyZWQgKG5vIGxvbmdlciA9IGEyMSkKIyB0aGVyZWZvcmUsIGEyMSA9IHBhclszXSAqIHBhclsxXQptb2RGdW5fMnAgPC0gZnVuY3Rpb24ocGFycywgSW4sIGxhZyA9IDAsIHBhc3MgPSBUUlVFLCBvdXQgPSAibW9kRml0IiwgbW9kKSB7CiAKICAjIGludGlhbCAxNEMKICBGMF9EZWx0YTE0QyA8LSB1bmxpc3QobGFwcGx5KHBhcnNbMToyXSwgZnVuY3Rpb24oeCkgRGVsdGExNENfZnJvbV9BYnNvbHV0ZUZyYWN0aW9uTW9kZXJuKGZtKHgpKSkpCiAgCiAgIyBtb2RlbCBtYXRyaXgKICBBIDwtIC1kaWFnKHBhcnNbMToyXSkKICBpZiAobW9kID09ICIycHMiKSB7CiAgICBhMjEgPC0gcGFyc1szXSAqIHBhcnNbMV0KICAgIEFbMiwgMV0gPC0gYTIxCiAgfQogICAgCiAgIyBzdGVhZHktc3RhdGUgQyBzdG9ja3MKICBpZiAobW9kID09ICIycHAiKSB7CiAgICBzcy5jc3RvY2sgPC0gKC0xICogc29sdmUoQSkgJSolIGMoSW4gKiBwYXJzWzNdLCBJbiAqICgxIC0gcGFyc1szXSkpKQogIH0gZWxzZSB7CiAgICBzcy5jc3RvY2sgPC0gKC0xICogc29sdmUoQSkgJSolIGMoSW4sIDApKQogIH0KICAKICAjIHRpbWUgaW5kZXgKICBpeC50IDwtIGMoKGxhZyArIDEpOm5yb3coRGF0bSkpCiAgCiAgIyBtb2RlbAogIGlmIChtb2QgPT0gIjJwcCIpIHsKICAgIG1vZCA8LSBUd29wUGFyYWxsZWxNb2RlbDE0KHQgPSBEYXRtJERhdGVbaXgudF0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBrcyA9IHBhcnNbMToyXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEMwID0gYyhzcy5jc3RvY2tbMV0sIHNzLmNzdG9ja1syXSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBGMF9EZWx0YTE0QyA9IEYwX0RlbHRhMTRDLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgSW4gPSBJbiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdhbSA9IHBhcnNbM10sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbnB1dEZjID0gRGF0bSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhZyA9IGxhZywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhc3MgPSBwYXNzKQogIH0gZWxzZSB7CiAgICBtb2QgPC0gVHdvcFNlcmllc01vZGVsMTQodCA9IERhdG0kRGF0ZVtpeC50XSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBrcyA9IHBhcnNbMToyXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBDMCA9IGMoc3MuY3N0b2NrWzFdLCBzcy5jc3RvY2tbMl0pLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIEYwX0RlbHRhMTRDID0gRjBfRGVsdGExNEMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgSW4gPSBJbiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhMjEgPSBhMjEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5wdXRGYyA9IERhdG0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFnID0gbGFnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhc3MgPSBwYXNzKQogIH0KICAKICAjIGdldCBtb2QgdmFsdWVzCiAgQzE0bSA8LSBnZXRGMTRDKG1vZCkKICBDMTRwIDwtIGdldEYxNChtb2QpCiAgQzE0ciA8LSBnZXRGMTRSKG1vZCkKICBDdG90IDwtIGdldEMobW9kKQogIAogIGlmKG91dCA9PSAibW9kRml0IikgewogICAgIyBkYXRhZnJhbWUgZm9yIG1vZEZpdCBmeAogICAgcmV0dXJuKGRhdGEuZnJhbWUoCiAgICAgIHRpbWUgPSBEYXRtJERhdGVbaXgudF0sCiAgICAgIGJ1bGtDID0gQzE0bSwgCiAgICAgIHJlc3AgPSBDMTRyLAogICAgICBjU3RvY2sgPSByb3dTdW1zKEN0b3QpKSkKICB9IGVsc2UgewogICAgIyBkYXRhIGZyYW1lIGZvciBwbG90dGluZwogICAgcmV0dXJuKGRhdGEuZnJhbWUoCiAgICAgIHllYXJzID0gcmVwKERhdG0kRGF0ZVtpeC50XSwgNSksCiAgICAgIGQxNEMgPSBjKEMxNHBbLDFdLCAKICAgICAgICAgICAgICAgQzE0cFssMl0sIAogICAgICAgICAgICAgICBDMTRtLAogICAgICAgICAgICAgICBDMTRyLAogICAgICAgICAgICAgICBEYXRtJE5IYzE0W2l4LnRdKSwKICAgICAgcG9vbCA9IHJlcChjKCJmYXN0IiwgInNsb3ciLCAiYnVsayBDIiwgInJlc3BpcmF0aW9uIiwgImF0bSIpLCBlYWNoID0gbnJvdyhDMTRwKSkpKQogIH0KfQoKIyAxcCBtb2RGdW4KbW9kRnVuXzFwIDwtIGZ1bmN0aW9uKHBhcnMsIEluLCBsYWcgPSAwLCBvdXQgPSAibW9kRml0IiwgbW9kLCBwYXNzID0gVFJVRSkgewogCiAgIyBpbnRpYWwgMTRDCiAgRjBfRGVsdGExNEMgPC0gRGVsdGExNENfZnJvbV9BYnNvbHV0ZUZyYWN0aW9uTW9kZXJuKGZtKHBhcnMpKQogIAogICMgc3RlYWR5LXN0YXRlIEMgc3RvY2tzCiAgc3MuY3N0b2NrIDwtIEluL3BhcnMKICAKICAjIHRpbWUgaW5kZXgKICBpeC50IDwtIGMoKGxhZyArIDEpOm5yb3coRGF0bSkpCiAgCiAgIyBtb2RlbAogIG1vZCA8LSBzdXBwcmVzc1dhcm5pbmdzKAogICAgIyB3YXJuaW5ncyBzdXBwcmVzc2VkIGR1ZSB0byB0aGUgIkZjIiB3YXJuaW5nCiAgICBPbmVwTW9kZWwxNCh0ID0gRGF0bSREYXRlW2l4LnRdLAogICAgICAgICAgICAgICAgICAgICBrID0gcGFycywKICAgICAgICAgICAgICAgICAgICAgQzAgPSBzcy5jc3RvY2ssCiAgICAgICAgICAgICAgICAgICAgIEYwX0RlbHRhMTRDID0gRjBfRGVsdGExNEMsCiAgICAgICAgICAgICAgICAgICAgIEluID0gSW4sCiAgICAgICAgICAgICAgICAgICAgIGlucHV0RmMgPSBEYXRtLAogICAgICAgICAgICAgICAgICAgICBsYWcgPSBsYWcsCiAgICAgICAgICAgICAgICAgICAgIHBhc3MgPSBwYXNzKQogICkKICAKICAjIGdldCBtb2QgdmFsdWVzCiAgQzE0bSA8LSBnZXRGMTRDKG1vZCkKICBDdG90IDwtIGdldEMobW9kKQogIAogIGlmKG91dCA9PSAibW9kRml0IikgewogICAgIyBkYXRhZnJhbWUgZm9yIG1vZEZpdCBmeAogICAgcmV0dXJuKGRhdGEuZnJhbWUoCiAgICAgIHRpbWUgPSBEYXRtJERhdGVbaXgudF0sCiAgICAgIGJ1bGtDID0gQzE0bSwKICAgICAgY1N0b2NrID0gQ3RvdCkpCiAgfSBlbHNlIHsKICAgICMgZGF0YSBmcmFtZSBmb3IgcGxvdHRpbmcKICAgIHJldHVybihkYXRhLmZyYW1lKAogICAgICB5ZWFycyA9IHJlcChEYXRtJERhdGVbaXgudF0sIDEpLAogICAgICBkMTRDID0gYyhDMTRtLAogICAgICAgICAgICAgICBEYXRtJE5IYzE0W2l4LnRdKSwKICAgICAgcG9vbCA9IHJlcChjKCJidWxrIEMiLCAiYXRtIiksIGVhY2ggPSBsZW5ndGgoQzE0bSkpKSkKICB9Cn0KCiMgZnVuY3Rpb24gZm9yIHRyaWFsIGFuZCBlcnJvciBhcHByb2FjaCB0byBmaW5kaW5nIGluaXRpYWwgcGFyYW1ldGVyIHNldApwYXIuZnggPC0gZnVuY3Rpb24ocGFycywgSW4sIGxhZyA9IDAsIG91dCA9ICJwbG90LmRmIiwgdmVyYm9zZSA9IFRSVUUsIG1vZCwgcGFzcyA9IEZBTFNFKSB7CiAgCiAgIyBtb2RlbCBtYXRyaXgKICBBIDwtIC1kaWFnKHBhcnNbMToyXSkKICBpZiAobW9kID09ICIycHMiKSB7CiAgICBhMjEgPC0gcGFyc1szXSAqIHBhcnNbMV0KICAgIEFbMiwgMV0gPC0gYTIxCiAgICAjIHN0ZWFkeS1zdGF0ZSBzdG9ja3MKICAgIHNzLmNzdG9jayA8LSByb3VuZCgoLTEgKiBzb2x2ZShBKSAlKiUgYyhJbiwgMCkpLCAxKQogIH0gZWxzZSBpZiAobW9kID09ICIycHAiKSB7CiAgICAjIHN0ZWFkeS1zdGF0ZSBzdG9ja3MKICAgIHNzLmNzdG9jayA8LSByb3VuZCgoLTEgKiBzb2x2ZShBKSAlKiUgYyhJbiAqIHBhcnNbM10sIEluICogKDEgLSBwYXJzWzNdKSkpLCAxKQogIH0gZWxzZSB7CiAgICBzcy5jc3RvY2sgPC0gSW4vcGFycwogIH0KICAKICBjc3RvY2suc3VtIDwtIGlmZWxzZShsZW5ndGgoc3MuY3N0b2NrKSA9PSAxLCBzcy5jc3RvY2ssIGNvbFN1bXMoc3MuY3N0b2NrKSkKICAKICAjIHByaW50IHNpdGUgYW5kIHN0ZWFkeS1zdGF0ZSBzdG9ja3MKICBpZiAodmVyYm9zZSkgewogICAgY2F0KHBhc3RlMChQTWVjb19kZXB0aCwgIlxuIikpCiAgICBpZiAobW9kID09ICIycHMiIHwgbW9kID09ICIycHAiKSB7CiAgICAgIGNhdChwYXN0ZTAoc3MuY3N0b2NrWzFdLCAiIChmYXN0IHBvb2wpXG4iLCBzcy5jc3RvY2tbMl0sICIgKHNsb3cgcG9vbClcbiIpKQogICAgICBjYXQocGFzdGUwKCJzbG93IHBvb2w6ICIsIHJvdW5kKHNzLmNzdG9ja1syXSAvIGNzdG9jay5zdW0gKiAxMDAsIDApLCAiJVxuIikpIAogICAgfQogICAgY2F0KHJvdW5kKGNzdG9jay5zdW0sIDEpLCAiIChtb2RlbGVkIHN0b2NrcylcbiIpCiAgICBjYXQocm91bmQoY3NvYy4xOS4wXzMwW1tQTWVjb19kZXB0aF1dWyAsICJseXJfc29jIl0sIDEpLCAiIChtZWFzdXJlZCBzdG9ja3MpXG4iKSAKICB9CiAgaWYgKG1vZCA9PSAiMXAiKSB7CiAgICByZXR1cm4obW9kRnVuXzFwKHBhcnMgPSBwYXJzLCBJbiA9IEluLCBsYWcgPSBsYWcsIG91dCA9IG91dCwgbW9kID0gIjFwIiwgcGFzcyA9IHBhc3MpKQogIH0KICBpZiAobW9kID09ICIycHAiKSB7CiAgIHJldHVybihtb2RGdW5fMnAocGFycyA9IHBhcnMsIEluID0gSW4sIGxhZyA9IGxhZywgb3V0ID0gb3V0LCBtb2QgPSAiMnBwIiwgcGFzcyA9IHBhc3MpKSAKICB9IGVsc2UgaWYgKG1vZCA9PSAiMnBzIikgewogICAgcmV0dXJuKG1vZEZ1bl8ycChwYXJzID0gcGFycywgSW4gPSBJbiwgbGFnID0gbGFnLCBvdXQgPSBvdXQsIG1vZCA9ICIycHMiLCBwYXNzID0gcGFzcykpIAogIH0KfQpgYGAKCmBgYHtyIGlucHV0cy1zdG9ja3N9CiMjIGFkanVzdCBpbnB1dHMgdG8gbWF0Y2ggc3RvY2tzCiMgZnVuY3Rpb24gZm9yIGNhbGN1bGF0aW5nIHN0ZWFkeS1zdGF0ZSBTT0Mgc3RvY2tzCnNvYy5meCA8LSBmdW5jdGlvbihtb2RTdHIsIHBhcnMsIEluLCBvdXQgPSAicG9vbHMiKSB7CiAgaWYgKG1vZFN0ciA9PSAiMnBwIikgewogICAgY21hdCA8LSAtMSAqIHNvbHZlKC1kaWFnKHBhcnNbMToyXSkpICUqJSBjKEluICogcGFyc1szXSwgSW4gKiAoMSAtIHBhcnNbM10pKQogIH0gZWxzZSB7CiAgICBBIDwtIC1kaWFnKHBhcnNbMToyXSkKICAgIEFbMiwgMV0gPC0gcGFyc1szXSAjIG5vdGUgdGhhdCBhMjEgZGVmaW5lZCBhcyBwY3QgdHJhbnNmZXIgKiBrMQogICAgY21hdCA8LSAtMSAqIHNvbHZlKEEpICUqJSBjKEluLCAwKSAjIEluIGlzIHRvdGFsIGlucHV0IGludG8gdGhlIHN5c3RlbQogIH0KICBpZiAob3V0ID09ICJwb29scyIpIHsKICAgIHJldHVybihjbWF0KQogIH0gZWxzZSB7CiAgICByZXR1cm4oY29sU3VtcyhjbWF0KSkKICB9Cn0KCmluLmZpdC5meCA8LSBmdW5jdGlvbihtb2RTdHIsIHBhcnMsIGluaXRpYWxJbiwgU09DKSB7CiAgIyBzZXF1ZW5jZSBvZiBwb3NzaWJsZSBpbnB1dCB2YWx1ZXMKICBpZiAgKFNPQyA8IHNvYy5meChtb2RTdHIsIHBhcnMsIGluaXRpYWxJbiwgb3V0ID0gInN1bSIpKSB7CiAgICBpbnMgPC0gc2VxKC4wMSwgCiAgICAgICAgICAgICAgIGluaXRpYWxJbiwgCiAgICAgICAgICAgICAgIC4wMSkKICAgIH0gZWxzZSB7CiAgICAgIGlucyA8LSBzZXEoaW5pdGlhbEluLCAKICAgICAgICAgICAgICAgICBTT0MsIAogICAgICAgICAgICAgICAgIC4wMSkKICAgIH0KICAjIG1vZGVsZWQgc3RvY2tzCiAgc29jX21vZCA8LSBsYXBwbHkoc2VxX2Fsb25nKGlucyksIGZ1bmN0aW9uKGopIHsKICAgIHNvYy5meChtb2RTdHIsIHBhcnMsIGluc1tqXSwgb3V0ID0gInN1bSIpCiAgfSkKICBpeCA8LSB3aGljaC5taW4oYWJzKHVubGlzdChzb2NfbW9kKSAtIFNPQykpCiAgcmV0dXJuKGluc1tpeF0pCn0KCiMgbG9hZCBpbml0aWFsIHBhcmFtZXRlciBzZXQKbG9hZCgiLi4vZGF0YS9kZXJpdmVkL21vZEZpdF9wYXJzL3BhcnMuaS4ycHBfMjAyMS0wMy0zMC5SZGF0YSIpCmxvYWQoIi4uL2RhdGEvZGVyaXZlZC9tb2RGaXRfcGFycy9wYXJzLmkuMnBzXzIwMjAtMTEtMTYuUmRhdGEiKQoKIyMgaW5wdXRzIGZvciBpbml0aWFsIHBhciBzZXQgYW5kIG1lYXN1cmVkIHN0b2NrcwojIDJwcAppbi5tZWFzLjJwcCA8LSBsYXBwbHkoc2VxX2Fsb25nKHBhcnMuaS4ycHBbaXguMTBdKSwgZnVuY3Rpb24oaSkgewogIFBNZWNvX2RlcHRoIDwtIG5hbWVzKHBhcnMuaS4ycHBbaXguMTBdKVtpXQogIFNPQyA8LSBjc29jLjE5LjBfMzBbW1BNZWNvX2RlcHRoXV1bICwibHlyX3NvYyJdCiAgcmV0dXJuKGluLmZpdC5meCgiMnBwIiwgcGFycy5pLjJwcFtpeC4xMF1bW2ldXSwgaW4uaVtpeC4xMF1bW2ldXSwgU09DKSkKfSkKbmFtZXMoaW4ubWVhcy4ycHApIDwtIG5hbWVzKHBhcnMuaS4ycHBbaXguMTBdKQojIDJwcwppbi5tZWFzLjJwcyA8LSBsYXBwbHkoc2VxX2Fsb25nKHBhcnMuaS4ycHNbaXguMTBdKSwgZnVuY3Rpb24oaSkgewogIFBNZWNvX2RlcHRoIDwtIG5hbWVzKHBhcnMuaS4ycHNbaXguMTBdKVtpXQogIFNPQyA8LSBjc29jLjE5LjBfMzBbW1BNZWNvX2RlcHRoXV1bICwibHlyX3NvYyJdCiAgcmV0dXJuKGluLmZpdC5meCgiMnBwIiwgcGFycy5pLjJwc1tpeC4xMF1bW2ldXSwgaW4uaVtpeC4xMF1bW2ldXSwgU09DKSkKfSkKbmFtZXMoaW4ubWVhcy4ycHMpIDwtIG5hbWVzKHBhcnMuaS4ycHNbaXguMTBdKQoKIyBGbHV4IGVzdGltYXRlZCBmcm9tIEdvdWxkZW4gZXQgYWwuIDIwMTI7IFRhbmcgZXQgYWwuIDIwMDU7IFdhbmcgZXQgYWwuIDIwMDA7IEdhdWRpbnNraSAyMDAwCiMgZmx1eGVzIGJ5IGVsZXZhdGlvbiBmcm9tIEdQUCByZXBvcnRlZCBpbiBHb3VsZGVuIGV0IGFsLiBGaWcuIDUgYW5kIGFwcHJveGltYXRlZAojIFJoIHBlcmNlbnRhZ2UgZnJvbSBUYW5nIGV0IGFsLiAyMDA1ID0gMC40NCAoYW5uLiBtZWFuIEJsb2RnZXR0KTsgY2YuIDAuNDggSGFydmFyZCBGb3Jlc3QKIyBBIGhvcml6b24gZXN0LiAwLjU1IGZyb20gR2F1ZGluc2tpCiMgYXNzdW1pbmcgQSA9IDAtMzAsIGFzc3VtZSAwLTEwID0gNTAlLCAxMC0yMCA9IDMwJSwgMjAtMzAgPSAyMCUgb2YgdG90YWwgQSBwcm9kdWN0aW9uIApoem5BLlJoLmtnbTIgPC0gMC40NCAqIDAuNTUgKiAxMF4tMwpncHAubHMgPC0gYygxODAwLCAxNjAwLCAxNDAwKQppbi5mcmMubHMgPC0gYygwLjUsIDAuMywgMC4yKQoKIyBmeCBmb3IgY2FsY3VsYXRpbmcgaW5wdXRzCmluLmZseC5meCA8LSBmdW5jdGlvbihQTWVjb19kZXB0aCkgewogIGdwcCA8LSBpZmVsc2UoZ3JlcGwoInBwIiwgUE1lY29fZGVwdGgpLCBncHAubHNbMV0sIGlmZWxzZShncmVwbCgid2YiLCBQTWVjb19kZXB0aCksIGdwcC5sc1syXSwgZ3BwLmxzWzNdKSkKICBpbi5mcmMgPC0gaWZlbHNlKGdyZXBsKCIwLTEwIiwgUE1lY29fZGVwdGgpLCBpbi5mcmMubHNbMV0sIGlmZWxzZShncmVwbCgiMTAtMjAiLCBQTWVjb19kZXB0aCksIGluLmZyYy5sc1syXSwgaW4uZnJjLmxzWzNdKSkKICByZXR1cm4oZ3BwICogaW4uZnJjICogaHpuQS5SaC5rZ20yKQp9CgojIGlucHV0IGxpc3QKaW4uZXN0IDwtIGxhcHBseShzZXFfYWxvbmcocGFycy5pLjJwcCksIGZ1bmN0aW9uKGkpIHsKICBQTWVjb19kZXB0aCA8LSBuYW1lcyhwYXJzLmkuMnBwKVtpXQogIHJldHVybihpbi5mbHguZngoUE1lY29fZGVwdGgpKQp9KQpuYW1lcyhpbi5lc3QpIDwtIG5hbWVzKHBhcnMuaS4ycHApCmBgYAojIyBQYXJhbWV0ZXIgb3B0aW1pemF0aW9uCgpPcHRpbWl6aW5nIHRoZSBwYXJhbWV0ZXIgc2V0IHJlcXVpcmVzIGltcG9zaW5nIGNvc3RzIGFuZCBvcHRpb25hbGx5IGNvbnN0cmFpbmluZyB0aGUgYWxsb3dhYmxlIHJhbmdlIG9mIHZhbHVlcyBmb3IgZWFjaCBwYXJhbWV0ZXIuIEdpdmVuIHRoYXQgd2Ugb25seSBoYXZlIGRhdGEgZm9yIHRocmVlIHRpbWUgcG9pbnRzLCB0aGlzIGlzIGEgcmVsYXRpdmVseSBzcGFyc2UgZGF0YSBzZXQgZm9yIGNvbnN0cmFpbmluZyB0aGVzZSBtb2RlbHMuIEFjY29yZGluZ2x5LCB0aGUgb3B0aW1pemF0aW9uIHByb2NlZHVyZSB3aWxsIGJlbmVmaXQgZnJvbSAqYSBwcmlvcmkqIGNvbnN0cmFpbnRzIG9mIHRoZSBhbGxvd2FibGUgcGFyYW1ldGVyIHJhbmdlcy4gRm9yIGV4YW1wbGUsIHNpbmNlIHdlIGFzc3VtZSB0aGF0IHRoZSBzeXN0ZW0gY2Fubm90IGJlIGFkZXF1YXRlbHkgbW9kZWxlZCBhcyBhIHNpbmdsZSBob21vZ2Vub3VzIHJlc2Vydm9pciwgd2Ugd2lsbCBlbnN1cmUgdGhhdCB0aGUgb3B0aW1pemF0aW9uIHByb2NlZHVyZSBjYW5ub3QgY29sbGFwc2UgdGhlIHR3by1wb29sIHN5c3RlbSBpbnRvIGEgc2luZ2xlIHBvb2wuIFRoaXMgY2FuIGJlIG1pdGlnYXRlZCBpbiB0aGUgdHdvLXBvb2wgcGFyYWxsZWwgb3B0aW1pemF0aW9uIGJ5IGNvbnN0cmFpbmluZyAkXGdhbW1hJCAoaS5lLiB0aGUgcGVyY2VudGFnZSBvZiB0aGUgaW5wdXRzIGVudGVyaW5nIHRoZSBmYXN0IHBvb2wpIHRvIGEgcmFuZ2Ugb2YgNTAlIHRvIDk1JS4gU2ltaWxhcmx5LCBmb3IgdGhlIHR3by1wb29sIHNlcmllcyBtb2RlbCBzdHJ1Y3R1cmUgd2UgY2FuIGNvbnN0cmFpbiB0aGUgcmFuZ2Ugb2YgdGhlIHRyYW5zZmVyIGNvZWZmaWNpZW50IHRvIGJlIGJldHdlZW4gMC4wIGFuZCAwLjEsIGVuc3VyaW5nIHRoYXQgc29tZSBjYXJib24gcmVtYWlucyBpbiB0aGUgZmFzdCBjeWNsaW5nIHBvb2wuCgpBZGRpdGlvbmFsbHksIHRvIGVuZm9yY2UgYSByZWxhdGl2ZWx5IGZhc3QgY3ljbGluZyBwb29sIGFuZCByZWxhdGl2ZWx5IHNsb3dlciBjeWNsaW5nIHBvb2wsIHdlIHdpbGwgbG9vc2VseSBjb25zdHJhaW4gdGhlIGludHJpbnNpYyBkZWNvbXBvc2l0aW9uIHJhdGVzIGFzIHdlbGwgKGJvdGggbW9kZWwgc3RydWN0dXJlcyk6Cgoqa34xfio6IFswLjAyLCAxLjAwXSAoNTAgdG8gMSB5ZWFyKQoqa34yfio6IFswLjAwMDEsIDAuMDJdICgxMCwwMDAgdG8gNTAgeWVhcnMpCgpGaW5hbGx5LCB0aGUgbW9kZWxzIHdpbGwgYmUgcnVuIHRvIGVuZm9yY2Ugc3RlYWR5LXN0YXRlLCBpLmUuIHdpdGggdW52YXJ5aW5nIGNhcmJvbiBzdG9ja3MuIFRoZSBhbW91bnQgb2YgY2FyYm9uIG9ic2VydmVkIGluIHRoZSBzeXN0ZW0gd2lsbCBiZSB1c2VkIGluIHRoZSBjb3N0IGZ1bmN0aW9uIGluIGFkZGl0aW9uIHRvIHRoZSByYWRpb2NhcmJvbiBvYnNlcnZhdGlvbnMgbWFkZSBpbiAyMDAxLCAyMDA5LCBhbmQgMjAxOS4gVGhlIGlucHV0cyB3aWxsIGJlIGVzdGltYXRlZCBmcm9tIG5ldCBlY29zeXN0ZW0gZXhjaGFuZ2UgKE5FRSkgZGF0YSBtZWFzdXJlZCBhdCBuZWFyYnkgZWRkeSBjb3ZhcmlhbmNlIHNpdGVzOiBCbG9kZ2V0dCBleHBlcmltZW50YWwgZm9yZXN0IChBbWVyaUZsdXgpLCBMb3dlciBUZWFrZXR0bGUgKE5FT04pLCBhbmQgU29hcHJvb3QgU2FkZGxlIChORU9OKS4gQWx0ZXJuYXRpdmVseSwgdXNpbmcgY29ycmVsYXRpb25zIGJldHdlZW4gZmx1eGVzIG1lYXN1cmVkIGZyb20gdGhlc2UgZWRkeSBjb3ZhcmlhbmNlIHRvd2VycyBhbmQgR1BQIGVzdGltYXRlZCBmcm9tIHNhdGVsbGl0ZSByZXRyaWV2YWxzIG9mIFNJRiwgZXN0aW1hdGVzIGNhbiBiZSBtYWRlIGZvciBpbnB1dHMgYXQgdGhlIHBpeGVscyBjb3JyZXNwb25kaW5nIHRvIGVhY2ggc2l0ZSBsb2NhdGlvbi4KCmBgYHtyIG9wdC1tb2QsIGV2YWwgPSBGQUxTRX0KIyBOb3RlOiB0aGlzIG9ubHkgcnVucyBpZiBldmFsIGZsYWcgc3dpdGNoZWQgdG8gVFJVRQojIyBPcHRpbWl6ZSBtb2RlbCBwYXJzCiMgQ29zdCBmdW5jdGlvbiAoZXZhbHVhdGVzIGVycm9yIGFzIG1vZGVsIHZzLiBvYnN2LCBwZXIgRk1FIHJlcSkKIyBub3RlIHRoYXQgd2UgaGF2ZSB0byBzZXQgInBhc3MiIHRvIFRSVUUgc28gU29pbFIgbW9kZWwgZG9lc24ndCBmYWlsIChuZWcuIHJlc3ApCm1vZC5maXRzLmZ4IDwtIGZ1bmN0aW9uKG1vZCwgcGFycywgSW4sIHN1YiwgbGFnID0gMCwgdXBwZXIsIGxvd2VyLCBjb3N0KSB7CiAgCiAgIyBzdGFydCBsb29wCiAgbGFwcGx5KHNlcV9hbG9uZyhwYXJzW3N1Yl0pLCBmdW5jdGlvbihpKSB7CiAgICAKICAgICMgc3RhcnQgdGltZXIgYW5kIHByaW50IFBNZWNvX2RlcHRoCiAgICBzdGFydCA8LSBTeXMudGltZSgpCiAgICBjYXQocGFzdGUwKG5hbWVzKHBhcnMpW3N1Yl1baV0sICIgcGFyYW1ldGVyIGZpdHRpbmdcbiIpKQogIAogICAgIyBkZWZpbmUgcGFycwogICAgcGFycyA8LSBwYXJzW3N1Yl1bW2ldXQogICAgaWYgKG1vZCA9PSAiMnBwIikgewogICAgICBuYW1lcyhwYXJzKSA8LSBjKCJrMSIsICJrMiIsICJnYW0iKQogICAgfSBlbHNlIHsKICAgICAgbmFtZXMocGFycykgPC0gYygiazEiLCAiazIiLCAidGMiKQogICAgfQogICAgCiAgICAjIFNldCBpbnB1dAogICAgSW4gPC0gSW5bc3ViXVtbaV1dCiAgICAKICAgICMgZGVmaW5lIGNvc3QgZnVuY3Rpb24KICAgIGlmIChjb3N0ID09ICIxNEMgKyBjU3RvY2siKSB7CiAgICAgIG1vZC5Db3N0IDwtIGZ1bmN0aW9uKHBhcnMpIHsKICAgICAgICBtb2RlbE91dHB1dCA8LSBtb2RGdW5fMnAocGFycywgSW4sIG1vZCA9IG1vZCwgbGFnID0gbGFnKQogICAgICAgIGNvc3QxIDwtIG1vZENvc3QobW9kZWwgPSBtb2RlbE91dHB1dCwgb2JzID0gb2JzLmJ1bGsuMTRjW3N1Yl1bW2ldXSwgc2NhbGVWYXIgPSBUUlVFKQogICAgICAgIGNvc3QyIDwtIG1vZENvc3QobW9kZWwgPSBtb2RlbE91dHB1dCwgb2JzID0gb2JzLnJlc3AuMTRjW3N1Yl1bW2ldXSwgc2NhbGVWYXIgPSBUUlVFLCBjb3N0ID0gY29zdDEpIAogICAgICAgIHJldHVybihtb2RDb3N0KG1vZGVsID0gbW9kZWxPdXRwdXQsIG9icyA9IG9icy5jU3RvY2tbc3ViXVtbaV1dLCBjb3N0ID0gY29zdDIpKQogICAgICB9CiAgICB9IGVsc2UgaWYgKGNvc3QgPT0gIjE0QyArIHN0b2NrL2ZseCIpIHsKICAgICAgbW9kLkNvc3QgPC0gZnVuY3Rpb24ocGFycykgewogICAgICAgIG1vZGVsT3V0cHV0IDwtIG1vZEZ1bl8ycChwYXJzLCBJbiwgbW9kID0gbW9kLCBsYWcgPSBsYWcpCiAgICAgICAgY29zdDEgPC0gbW9kQ29zdChtb2RlbCA9IG1vZGVsT3V0cHV0LCBvYnMgPSBvYnMuYnVsay4xNGNbc3ViXVtbaV1dLCBzY2FsZVZhciA9IFRSVUUpCiAgICAgICAgY29zdDIgPC0gbW9kQ29zdChtb2RlbCA9IG1vZGVsT3V0cHV0LCBvYnMgPSBvYnMucmVzcC4xNGNbc3ViXVtbaV1dLCBzY2FsZVZhciA9IFRSVUUsIGNvc3QgPSBjb3N0MSkgCiAgICAgICAgcmV0dXJuKG1vZENvc3QobW9kZWwgPSBtb2RlbE91dHB1dCwgb2JzID0gb2JzLmZseC5zdG9ja1tbaV1dLCBjb3N0ID0gY29zdDIpKQogICAgICB9CiAgICB9IGVsc2UgaWYgKGNvc3QgPT0gIjE0QyIpIHsKICAgICAgbW9kLkNvc3QgPC0gZnVuY3Rpb24ocGFycykgewogICAgICAgIG1vZGVsT3V0cHV0IDwtIG1vZEZ1bl8ycChwYXJzLCBJbiwgbW9kID0gbW9kLCBsYWcgPSBsYWcpCiAgICAgICAgY29zdDEgPC0gbW9kQ29zdChtb2RlbCA9IG1vZGVsT3V0cHV0LCBvYnMgPSBvYnMuYnVsay4xNGNbc3ViXVtbaV1dLCBzY2FsZVZhciA9IFRSVUUpCiAgICAgICAgcmV0dXJuKG1vZENvc3QobW9kZWwgPSBtb2RlbE91dHB1dCwgb2JzID0gb2JzLnJlc3AuMTRjW3N1Yl1bW2ldXSwgc2NhbGVWYXIgPSBUUlVFLCBjb3N0ID0gY29zdDEpKQogICAgICB9IAogICAgfSBlbHNlIGlmIChjb3N0ID09ICIxNEMgYnVsayArIGNTdG9jayIpIHsKICAgICAgbW9kLkNvc3QgPC0gZnVuY3Rpb24ocGFycykgewogICAgICAgIG1vZGVsT3V0cHV0IDwtIG1vZEZ1bl8ycChwYXJzLCBJbiwgbW9kID0gbW9kLCBsYWcgPSBsYWcpCiAgICAgICAgY29zdDEgPC0gbW9kQ29zdChtb2RlbCA9IG1vZGVsT3V0cHV0LCBvYnMgPSBvYnMuYnVsay4xNGNbc3ViXVtbaV1dLCBzY2FsZVZhciA9IFRSVUUpCiAgICAgICAgcmV0dXJuKG1vZENvc3QobW9kZWwgPSBtb2RlbE91dHB1dCwgb2JzID0gb2JzLmNTdG9ja1tzdWJdW1tpXV0sIGNvc3QgPSBjb3N0MSkpCiAgICAgIH0KICAgIH0gZWxzZSBpZiAoY29zdCA9PSAiMTRDIGJ1bGsgb25seSIpIHsKICAgICAgbW9kLkNvc3QgPC0gZnVuY3Rpb24ocGFycykgewogICAgICAgIG1vZGVsT3V0cHV0IDwtIG1vZEZ1bl8ycChwYXJzLCBJbiwgbW9kID0gbW9kLCBsYWcgPSBsYWcpCiAgICAgICAgcmV0dXJuKG1vZENvc3QobW9kZWwgPSBtb2RlbE91dHB1dCwgb2JzID0gb2JzLmJ1bGsuMTRjW3N1Yl1bW2ldXSwgc2NhbGVWYXIgPSBUUlVFKSkKICAgICAgfQogICAgfQogICAgCiAgICAjIGZpdCBwYXJzCiAgICBmaXQgPC0gdHJ5Q2F0Y2goCiAgICAgIG1vZEZpdChmID0gbW9kLkNvc3QsCiAgICAgICAgICAgICBwID0gcGFycywKICAgICAgICAgICAgIG1ldGhvZCA9ICdOZWxkZXItTWVhZCcsCiAgICAgICAgICAgICB1cHBlciA9IHVwcGVyLCAKICAgICAgICAgICAgIGxvd2VyID0gbG93ZXIpLAogICAgICBlcnJvciA9IGZ1bmN0aW9uIChlKSB7Y2F0KCJFUlJPUiA6IiwgY29uZGl0aW9uTWVzc2FnZShlKSwgIlxuIil9KQogICAgCiAgICBTZnVuIDwtIHNlbnNGdW4obW9kLkNvc3QsIGZpdCRwYXIpCiAgICAKICAgICMgRW5kIHRpbWVyIGFuZCBwcmludCBlbGFwc2VkIHRpbWUKICAgIGVuZCA8LSBTeXMudGltZSgpCiAgICBjYXQocGFzdGUwKCJ0aW1lOiAiLCBlbmQgLSBzdGFydCwgIlxuIikpCiAgICAKICAgICMgUmV0dXJuIGZpdHRlZCBwYXJhbWV0ZXJzIGFuZCBzZW5zaXRpdml0eQogICAgcmV0dXJuKGxpc3QobW9kZml0ID0gZml0LCBzZW5zID0gU2Z1bikpCiAgfSkgCn0KCiMjIDJwcAojIHBhciByYW5nZSBbMCwgMV0gZm9yIGFsbCBwYXJzCm1vZC5zZW5zLmZpdHMuMnBwIDwtIG1vZC5maXRzLmZ4KG1vZCA9ICIycHAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJzID0gcGFycy5pLjJwcCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgSW4gPSBpbi5pLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdWIgPSBpeC4xMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdXBwZXIgPSBjKDEsIDEsIDEpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb3dlciA9IGMoMCwgMCwgMCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvc3QgPSAiMTRDIikKbmFtZXMobW9kLnNlbnMuZml0cy4ycHApIDwtIG5hbWVzKHBhcnMuaS4ycHApW2l4LjEwXQpzYXZlKG1vZC5zZW5zLmZpdHMuMnBwLCBmaWxlID0gcGFzdGUwKCIuLi9kYXRhL2Rlcml2ZWQvbW9kRml0X3BhcnMvIiwgIm1vZC5maXRzLjJwcCIsICJfIiwgU3lzLkRhdGUoKSwgIi5SZGF0YSIpKQptb2QuZml0cy4ycHAgPC0gbGFwcGx5KG1vZC5zZW5zLmZpdHMuMnBwLCBmdW5jdGlvbih4KSB4W1sxXV0pCiMgY29uc3RyYWluIGdhbW1hIHRvIFswLjUsIDAuOTVdCm1vZC5zZW5zLmZpdHMuMnBwLnAzLjUuOTUgPC0gbW9kLmZpdHMuZngobW9kID0gIjJwcCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcnMgPSBwYXJzLmkuMnBwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdWIgPSBpeC4xMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgSW4gPSBpbi5pLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1cHBlciA9IGMoMSwgMSwgMC45NTEpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb3dlciA9IGMoMCwgMCwgMC41KSkKbmFtZXMobW9kLnNlbnMuZml0cy4ycHAucDMuNS45NSkgPC0gbmFtZXMocGFycy5pLjJwcClbaXguMTBdCnNhdmUobW9kLnNlbnMuZml0cy4ycHAucDMuNS45NSwgZmlsZSA9IHBhc3RlMCgiLi4vZGF0YS9kZXJpdmVkL21vZEZpdF9wYXJzLyIsICJtb2QuZml0cy4ycHAucDMuNS45NSIsICJfIiwgU3lzLkRhdGUoKSwgIi5SZGF0YSIpKQptb2QuZml0cy4ycHAucDMuNS45NSA8LSBsYXBwbHkobW9kLnNlbnMuZml0cy4ycHAucDMuNS45NSwgZnVuY3Rpb24oeCkgeFtbMV1dKQoKIyAycHAzIChwYXIgcmFuZ2UgY29uc3RyYWludHMsIGlucHV0cyBmaXQgdG8gbWVhcyBzdG9ja3MpCm1vZC5zZW5zLmZpdHMuMnBwMyA8LSBtb2QuZml0cy5meChtb2QgPSAiMnBwIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcnMgPSBwYXJzLmkuMnBwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3ViID0gaXguMTAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBJbiA9IGluLm1lYXMuMnBwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdXBwZXIgPSBjKDEsIC4wMiwgLjk1MSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb3dlciA9IGMoLjA0LCAuMDAwMSwgLjUpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29zdCA9ICIxNEMgb25seSIpCm5hbWVzKG1vZC5zZW5zLmZpdHMuMnBwMykgPC0gbmFtZXMocGFycy5pLjJwcClbaXguMTBdCnNhdmUobW9kLnNlbnMuZml0cy4ycHAzLCBmaWxlID0gcGFzdGUwKCIuLi9kYXRhL2Rlcml2ZWQvbW9kRml0X3BhcnMvIiwgIm1vZC5maXRzLjJwcDMiLCAiXyIsIFN5cy5EYXRlKCksICIuUmRhdGEiKSkKbW9kLmZpdHMuMnBwMyA8LSBsYXBwbHkobW9kLnNlbnMuZml0cy4ycHAzLCBmdW5jdGlvbih4KSB4W1sxXV0pCiMgMnBwM3MgKHBhciByYW5nZSBjb25zdHJhaW50cywgaW5wdXRzIGZpdCB0byBtZWFzIHN0b2NrcywgKyBzdG9jayBjb25zdHJhaW50KQptb2Quc2Vucy5maXRzLjJwcDNzIDwtIG1vZC5maXRzLmZ4KG1vZCA9ICIycHAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcnMgPSBwYXJzLmkuMnBwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1YiA9IGl4LjEwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEluID0gaW4ubWVhcy4ycHAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdXBwZXIgPSBjKDEsIC4wMiwgLjk1MSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG93ZXIgPSBjKC4wNCwgLjAwMDEsIC41KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb3N0ID0gImNTdG9jayIpCm5hbWVzKG1vZC5zZW5zLmZpdHMuMnBwM3MpIDwtIG5hbWVzKHBhcnMuaS4ycHApW2l4LjEwXQpzYXZlKG1vZC5zZW5zLmZpdHMuMnBwM3MsIGZpbGUgPSBwYXN0ZTAoIi4uL2RhdGEvZGVyaXZlZC9tb2RGaXRfcGFycy8iLCAibW9kLmZpdHMuMnBwM3MiLCAiXyIsIFN5cy5EYXRlKCksICIuUmRhdGEiKSkKbW9kLmZpdHMuMnBwM3MgPC0gbGFwcGx5KG1vZC5zZW5zLmZpdHMuMnBwM3MsIGZ1bmN0aW9uKHgpIHhbWzFdXSkKCiMjIDJwcwojIHBhciByYW5nZSBbMCwgMV0gZm9yIGFsbCBwYXJzCm1vZC5zZW5zLmZpdHMuMnBzIDwtIG1vZC5maXRzLmZ4KG1vZCA9ICIycHMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJzID0gcGFycy5pLjJwcywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1YiA9IGl4LjEwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBJbiA9IGluLmksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVwcGVyID0gYygxLCAxLCAxKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG93ZXIgPSBjKDAsIDAsIDApLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb3N0ID0gIjE0QyIpCm5hbWVzKG1vZC5zZW5zLmZpdHMuMnBzKSA8LSBuYW1lcyhwYXJzLmkuMnBzKVtpeC4xMF0Kc2F2ZShtb2Quc2Vucy5maXRzLjJwcywgZmlsZSA9IHBhc3RlMCgiLi4vZGF0YS9kZXJpdmVkL21vZEZpdF9wYXJzLyIsICJtb2QuZml0cy4ycHMiLCAiXyIsIFN5cy5EYXRlKCksICIuUmRhdGEiKSkKbW9kLmZpdHMuMnBzIDwtIGxhcHBseShtb2Quc2Vucy5maXRzLjJwcywgZnVuY3Rpb24oeCkgeFtbMV1dKQoKIyBwYXIgcmFuZ2UgWzAsIDFdIGZvciBhbGwgcGFycywgc3RvY2tzICsgMTRDLCB3LyBlc3RpbWF0ZWQgaW5wdXRzCiMgMTAKbW9kLnNlbnMuZml0cy4ycHM1LjEwIDwtIG1vZC5maXRzLmZ4KG1vZCA9ICIycHMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFycyA9IHBhcnMuaS4ycHMsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3ViID0gaXguMTAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBJbiA9IGluLmVzdCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVwcGVyID0gYygxLCAxLCAxKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvd2VyID0gYygwLCAwLCAwKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvc3QgPSAiMTRDICsgY1N0b2NrIikKbmFtZXMobW9kLnNlbnMuZml0cy4ycHM1LjEwKSA8LSBuYW1lcyhwYXJzLmkuMnBzKVtpeC4xMF0Kc2F2ZShtb2Quc2Vucy5maXRzLjJwczUuMTAsIGZpbGUgPSBwYXN0ZTAoIi4uL2RhdGEvZGVyaXZlZC9tb2RGaXRfcGFycy8iLCAibW9kLnNlbnMuZml0cy4ycHM1LjEwIiwgIl8iLCBTeXMuRGF0ZSgpLCAiLlJkYXRhIikpCm1vZC5maXRzLjJwczUuMTAgPC0gbGFwcGx5KG1vZC5zZW5zLmZpdHMuMnBzNS4xMCwgZnVuY3Rpb24oeCkgeFtbMV1dKQojIDIwCm1vZC5zZW5zLmZpdHMuMnBzNS4yMCA8LSBtb2QuZml0cy5meChtb2QgPSAiMnBzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcnMgPSBwYXJzLmkuMnBzLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1YiA9IGl4LjIwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgSW4gPSBpbi5lc3QsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1cHBlciA9IGMoMSwgMSwgMSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb3dlciA9IGMoMCwgMCwgMCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb3N0ID0gIjE0QyArIGNTdG9jayIpCm5hbWVzKG1vZC5zZW5zLmZpdHMuMnBzNS4yMCkgPC0gbmFtZXMocGFycy5pLjJwcylbaXguMjBdCnNhdmUobW9kLnNlbnMuZml0cy4ycHM1LjIwLCBmaWxlID0gcGFzdGUwKCIuLi9kYXRhL2Rlcml2ZWQvbW9kRml0X3BhcnMvIiwgIm1vZC5zZW5zLmZpdHMuMnBzNS4yMCIsICJfIiwgU3lzLkRhdGUoKSwgIi5SZGF0YSIpKQptb2QuZml0cy4ycHM1LjIwIDwtIGxhcHBseShtb2Quc2Vucy5maXRzLjJwczUuMjAsIGZ1bmN0aW9uKHgpIHhbWzFdXSkKCiMgMjAtMzAKbW9kLnNlbnMuZml0cy4ycHMuMzAgPC0gbW9kLmZpdHMuZngobW9kID0gIjJwcyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcnMgPSBwYXJzLmkuMnBzLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3ViID0gaXguMzAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEluID0gaW4uaSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdXBwZXIgPSBjKDEsIDEsIDEpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb3dlciA9IGMoMCwgMCwgMCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvc3QgPSAiMTRDIikKbmFtZXMobW9kLnNlbnMuZml0cy4ycHMuMzApIDwtIG5hbWVzKHBhcnMuaS4ycHMpW2l4LjMwXQpzYXZlKG1vZC5zZW5zLmZpdHMuMnBzLjMwLCBmaWxlID0gcGFzdGUwKCIuLi9kYXRhL2Rlcml2ZWQvbW9kRml0X3BhcnMvIiwgIm1vZC5maXRzLjJwcy4zMCIsICJfIiwgU3lzLkRhdGUoKSwgIi5SZGF0YSIpKQptb2QuZml0cy4ycHMuMzAgPC0gbGFwcGx5KG1vZC5zZW5zLmZpdHMuMnBzLjMwLCBmdW5jdGlvbih4KSB4W1sxXV0pCgojIDJwczMgKHBhciByYW5nZSBjb25zdHJhaW50cywgaW5wdXRzIGZpdCB0byBtZWFzIHN0b2NrcykKbW9kLnNlbnMuZml0cy4ycHMzIDwtIG1vZC5maXRzLmZ4KG1vZCA9ICIycHMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFycyA9IHBhcnMuaS4ycHMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdWIgPSBpeC4xMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEluID0gaW4ubWVhcy4ycHMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1cHBlciA9IGMoMSwgMSwgLjE1KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvd2VyID0gYygwLCAwLCAuMDAwNCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb3N0ID0gIjE0QyBvbmx5IikKbmFtZXMobW9kLnNlbnMuZml0cy4ycHMzKSA8LSBuYW1lcyhwYXJzLmkuMnBzKVtpeC4xMF0Kc2F2ZShtb2Quc2Vucy5maXRzLjJwczMsIGZpbGUgPSBwYXN0ZTAoIi4uL2RhdGEvZGVyaXZlZC9tb2RGaXRfcGFycy8iLCAibW9kLmZpdHMuMnBzMyIsICJfIiwgU3lzLkRhdGUoKSwgIi5SZGF0YSIpKQptb2QuZml0cy4ycHMzIDwtIGxhcHBseShtb2Quc2Vucy5maXRzLjJwczMsIGZ1bmN0aW9uKHgpIHhbWzFdXSkKIyAycHMzIChwYXIgcmFuZ2UgY29uc3RyYWludHMsIGlucHV0cyBmaXQgdG8gbWVhcyBzdG9ja3MsICsgc3RvY2sgY29uc3RyYWludCkKbW9kLnNlbnMuZml0cy4ycHMzcyA8LSBtb2QuZml0cy5meChtb2QgPSAiMnBzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJzID0gcGFycy5pLjJwcywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdWIgPSBpeC4xMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBJbiA9IGluLm1lYXMuMnBzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVwcGVyID0gYygxLCAuMDIsIC4xKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb3dlciA9IGMoLjA0LCAuMDAwMSwgMCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29zdCA9ICJjU3RvY2siKQpuYW1lcyhtb2Quc2Vucy5maXRzLjJwczNzKSA8LSBuYW1lcyhwYXJzLmkuMnBzKVtpeC4xMF0Kc2F2ZShtb2Quc2Vucy5maXRzLjJwczNzLCBmaWxlID0gcGFzdGUwKCIuLi9kYXRhL2Rlcml2ZWQvbW9kRml0X3BhcnMvIiwgIm1vZC5maXRzLjJwczNzIiwgIl8iLCBTeXMuRGF0ZSgpLCAiLlJkYXRhIikpCm1vZC5maXRzLjJwczNzIDwtIGxhcHBseShtb2Quc2Vucy5maXRzLjJwczNzLCBmdW5jdGlvbih4KSB4W1sxXV0pCgojIyMgMnA0IChwYXIgcmFuZ2Ugc2V0LCBzdG9jayBhbmQgYnVsayAxNEMgY29zdHMsIEdQUC1iYXNlZCBpbnB1dHMgYnkgZWNvKQojIyAycHAKIyAwLTEwCm1vZC5zZW5zLmZpdHMuMnBwNC4xMCA8LSBtb2QuZml0cy5meChtb2QgPSAiMnBwIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcnMgPSBwYXJzLmkuMnBwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3ViID0gaXguMTAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBJbiA9IGluLmVzdCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVwcGVyID0gYygxLCAuMDIsIC45NTEpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG93ZXIgPSBjKC4wNCwgLjAwMDEsIC41KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvc3QgPSAiMTRDIGJ1bGsgKyBjU3RvY2siKQpuYW1lcyhtb2Quc2Vucy5maXRzLjJwcDQuMTApIDwtIG5hbWVzKHBhcnMuaS4ycHApW2l4LjEwXQpzYXZlKG1vZC5zZW5zLmZpdHMuMnBwNC4xMCwgZmlsZSA9IHBhc3RlMCgiLi4vZGF0YS9kZXJpdmVkL21vZEZpdF9wYXJzLyIsICJtb2QuZml0cy4ycHA0LjEwIiwgIl8iLCBTeXMuRGF0ZSgpLCAiLlJkYXRhIikpCm1vZC5maXRzLjJwcDQuMTAgPC0gbGFwcGx5KG1vZC5zZW5zLmZpdHMuMnBwNC4xMCwgZnVuY3Rpb24oeCkgeFtbMV1dKQojIDIwLTMwCm1vZC5zZW5zLmZpdHMuMnBwNC4zMCA8LSBtb2QuZml0cy5meChtb2QgPSAiMnBwIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcnMgPSBwYXJzLmkuMnBwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3ViID0gaXguMzAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBJbiA9IGluLmVzdCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVwcGVyID0gYygxLCAuMDIsIC45NTEpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG93ZXIgPSBjKC4wNCwgLjAwMDEsIC41KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvc3QgPSAiMTRDIGJ1bGsgKyBjU3RvY2siKQpuYW1lcyhtb2Quc2Vucy5maXRzLjJwcDQuMzApIDwtIG5hbWVzKHBhcnMuaS4ycHApW2l4LjMwXQpzYXZlKG1vZC5zZW5zLmZpdHMuMnBwNC4zMCwgZmlsZSA9IHBhc3RlMCgiLi4vZGF0YS9kZXJpdmVkL21vZEZpdF9wYXJzLyIsICJtb2QuZml0cy4ycHA0LjMwIiwgIl8iLCBTeXMuRGF0ZSgpLCAiLlJkYXRhIikpCm1vZC5maXRzLjJwcDQuMzAgPC0gbGFwcGx5KG1vZC5zZW5zLmZpdHMuMnBwNC4zMCwgZnVuY3Rpb24oeCkgeFtbMV1dKQojIyAycHMKIyAwLTEwCm1vZC5zZW5zLmZpdHMuMnBzNC4xMCA8LSBtb2QuZml0cy5meChtb2QgPSAiMnBzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcnMgPSBwYXJzLmkuMnBzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3ViID0gaXguMTAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBJbiA9IGluLmVzdCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVwcGVyID0gYygxLCAuMDIsIC4xKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvd2VyID0gYyguMDQsIC4wMDAxLCAwKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvc3QgPSAiMTRDIGJ1bGsgKyBjU3RvY2siKQpuYW1lcyhtb2Quc2Vucy5maXRzLjJwczQuMTApIDwtIG5hbWVzKHBhcnMuaS4ycHMpW2l4LjEwXQpzYXZlKG1vZC5zZW5zLmZpdHMuMnBzNC4xMCwgZmlsZSA9IHBhc3RlMCgiLi4vZGF0YS9kZXJpdmVkL21vZEZpdF9wYXJzLyIsICJtb2QuZml0cy4ycHM0LjEwIiwgIl8iLCBTeXMuRGF0ZSgpLCAiLlJkYXRhIikpCm1vZC5maXRzLjJwczQuMTAgPC0gbGFwcGx5KG1vZC5zZW5zLmZpdHMuMnBzNC4xMCwgZnVuY3Rpb24oeCkgeFtbMV1dKQojIDIwLTMwCm1vZC5zZW5zLmZpdHMuMnBzNC4zMCA8LSBtb2QuZml0cy5meChtb2QgPSAiMnBzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcnMgPSBwYXJzLmkuMnBzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3ViID0gaXguMzAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBJbiA9IGluLmVzdCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVwcGVyID0gYygxLCAuMDIsIC4xKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvd2VyID0gYyguMDQsIC4wMDAxLCAwKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvc3QgPSAiMTRDIGJ1bGsgKyBjU3RvY2siKQpuYW1lcyhtb2Quc2Vucy5maXRzLjJwczQuMzApIDwtIG5hbWVzKHBhcnMuaS4ycHMpW2l4LjMwXQpzYXZlKG1vZC5zZW5zLmZpdHMuMnBzNC4zMCwgZmlsZSA9IHBhc3RlMCgiLi4vZGF0YS9kZXJpdmVkL21vZEZpdF9wYXJzLyIsICJtb2QuZml0cy4ycHM0LjMwIiwgIl8iLCBTeXMuRGF0ZSgpLCAiLlJkYXRhIikpCm1vZC5maXRzLjJwczQuMzAgPC0gbGFwcGx5KG1vZC5zZW5zLmZpdHMuMnBzNC4zMCwgZnVuY3Rpb24oeCkgeFtbMV1dKQoKIyMjIDJwNHIgKHBhciByYW5nZSBzZXQsIHN0b2NrLCBidWxrLCBhbmQgcmVzcGlyYXRpb24gMTRDIGNvc3RzLCBHUFAtYmFzZWQgaW5wdXRzIGJ5IGVjbykKIyMgMnBwCiMgMC0xMAptb2Quc2Vucy5maXRzLjJwcDRyLjEwIDwtIG1vZC5maXRzLmZ4KG1vZCA9ICIycHAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcnMgPSBwYXJzLmkuMnBwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1YiA9IGl4LjEwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEluID0gaW4uZXN0LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVwcGVyID0gYygxLCAuMDIsIC45NTEpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvd2VyID0gYyguMDQsIC4wMDAxLCAuNSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29zdCA9ICIxNEMgKyBjU3RvY2siKQpuYW1lcyhtb2Quc2Vucy5maXRzLjJwcDRyLjEwKSA8LSBuYW1lcyhwYXJzLmkuMnBwKVtpeC4xMF0Kc2F2ZShtb2Quc2Vucy5maXRzLjJwcDRyLjEwLCBmaWxlID0gcGFzdGUwKCIuLi9kYXRhL2Rlcml2ZWQvbW9kRml0X3BhcnMvIiwgIm1vZC5maXRzLjJwcDRyLjEwIiwgIl8iLCBTeXMuRGF0ZSgpLCAiLlJkYXRhIikpCm1vZC5maXRzLjJwcDRyLjEwIDwtIGxhcHBseShtb2Quc2Vucy5maXRzLjJwcDRyLjEwLCBmdW5jdGlvbih4KSB4W1sxXV0pCiMgMjAtMzAKbW9kLnNlbnMuZml0cy4ycHA0ci4zMCA8LSBtb2QuZml0cy5meChtb2QgPSAiMnBwIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJzID0gcGFycy5pLjJwcCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdWIgPSBpeC4zMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBJbiA9IGluLmVzdCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1cHBlciA9IGMoMSwgLjAyLCAuOTUxKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb3dlciA9IGMoLjA0LCAuMDAwMSwgLjUpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvc3QgPSAiMTRDICsgY1N0b2NrIikKbmFtZXMobW9kLnNlbnMuZml0cy4ycHA0ci4zMCkgPC0gbmFtZXMocGFycy5pLjJwcClbaXguMzBdCnNhdmUobW9kLnNlbnMuZml0cy4ycHA0ci4zMCwgZmlsZSA9IHBhc3RlMCgiLi4vZGF0YS9kZXJpdmVkL21vZEZpdF9wYXJzLyIsICJtb2QuZml0cy4ycHA0ci4zMCIsICJfIiwgU3lzLkRhdGUoKSwgIi5SZGF0YSIpKQptb2QuZml0cy4ycHA0ci4zMCA8LSBsYXBwbHkobW9kLnNlbnMuZml0cy4ycHA0ci4zMCwgZnVuY3Rpb24oeCkgeFtbMV1dKQojIyAycHMKIyAwLTEwCm1vZC5zZW5zLmZpdHMuMnBzNHIuMTAgPC0gbW9kLmZpdHMuZngobW9kID0gIjJwcyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFycyA9IHBhcnMuaS4ycHMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3ViID0gaXguMTAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgSW4gPSBpbi5lc3QsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdXBwZXIgPSBjKDEsIC4wMiwgLjEpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvd2VyID0gYyguMDQsIC4wMDAxLCAwKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb3N0ID0gIjE0QyArIGNTdG9jayIpCm5hbWVzKG1vZC5zZW5zLmZpdHMuMnBzNHIuMTApIDwtIG5hbWVzKHBhcnMuaS4ycHMpW2l4LjEwXQpzYXZlKG1vZC5zZW5zLmZpdHMuMnBzNHIuMTAsIGZpbGUgPSBwYXN0ZTAoIi4uL2RhdGEvZGVyaXZlZC9tb2RGaXRfcGFycy8iLCAibW9kLmZpdHMuMnBzNHIuMTAiLCAiXyIsIFN5cy5EYXRlKCksICIuUmRhdGEiKSkKbW9kLmZpdHMuMnBzNHIuMTAgPC0gbGFwcGx5KG1vZC5zZW5zLmZpdHMuMnBzNHIuMTAsIGZ1bmN0aW9uKHgpIHhbWzFdXSkKIyAyMC0zMAptb2Quc2Vucy5maXRzLjJwczRyLjMwIDwtIG1vZC5maXRzLmZ4KG1vZCA9ICIycHMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcnMgPSBwYXJzLmkuMnBzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1YiA9IGl4LjMwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEluID0gaW4uZXN0LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVwcGVyID0gYygxLCAuMDIsIC4xKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb3dlciA9IGMoLjA0LCAuMDAwMSwgMCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29zdCA9ICIxNEMgKyBjU3RvY2siKQpuYW1lcyhtb2Quc2Vucy5maXRzLjJwczRyLjMwKSA8LSBuYW1lcyhwYXJzLmkuMnBzKVtpeC4zMF0Kc2F2ZShtb2Quc2Vucy5maXRzLjJwczRyLjMwLCBmaWxlID0gcGFzdGUwKCIuLi9kYXRhL2Rlcml2ZWQvbW9kRml0X3BhcnMvIiwgIm1vZC5maXRzLjJwczRyLjMwIiwgIl8iLCBTeXMuRGF0ZSgpLCAiLlJkYXRhIikpCm1vZC5maXRzLjJwczRyLjMwIDwtIGxhcHBseShtb2Quc2Vucy5maXRzLjJwczRyLjMwLCBmdW5jdGlvbih4KSB4W1sxXV0pCmBgYAoKYGBge3IgcmVwb3J0LXBhci1maXR9CiMgbG9hZCBpbml0aWFsIHBhcmFtZXRlcnMgYXMgbmVlZGVkCmlmICghZXhpc3RzKCJwYXJzLmkuMnBwIikpIHsKIGxvYWQoIi4uL2RhdGEvZGVyaXZlZC9tb2RGaXRfcGFycy9wYXJzLmkuMnBwXzIwMjAtMTEtMTYuUmRhdGEiKSAKfQppZiAoIWV4aXN0cygicGFycy5pLjJwcyIpKSB7CiAgbG9hZCgiLi4vZGF0YS9kZXJpdmVkL21vZEZpdF9wYXJzL3BhcnMuaS4ycHNfMjAyMC0xMS0xNi5SZGF0YSIpICAKfQoKIyBsb2FkIGZpdHMgYXMgbmVlZGVkCmlmICghZXhpc3RzKCJtb2QuZml0cy4ycHAiKSkgewogbG9hZChmaWxlID0gIi4uL2RhdGEvZGVyaXZlZC9tb2RGaXRfcGFycy9tb2QuZml0cy4ycHBfMjAyMC0xMS0xNi5SRGF0YSIpCn0KaWYgKCFleGlzdHMoIm1vZC5maXRzLjJwcC5wMy41Ljk1IikpIHsKICBsb2FkKCIuLi9kYXRhL2Rlcml2ZWQvbW9kRml0X3BhcnMvbW9kLmZpdHMuMnBwLnAzLjUuOTVfMjAyMC0xMS0xNi5SZGF0YSIpICAKfQppZiAoIWV4aXN0cygibW9kLmZpdHMuMnBzIikpIHsKIGxvYWQoZmlsZSA9ICIuLi9kYXRhL2Rlcml2ZWQvbW9kRml0X3BhcnMvbW9kLmZpdHMuMnBzXzIwMjAtMTEtMTYuUmRhdGEiKQp9CmlmICghZXhpc3RzKCJtb2QuZml0cy4ycHAyIikpIHsKIGxvYWQoZmlsZSA9ICIuLi9kYXRhL2Rlcml2ZWQvbW9kRml0X3BhcnMvbW9kLmZpdHMuMnBwLmZseC5zdG9ja18yMDIwLTEyLTAyLlJEYXRhIikKfQppZiAoIWV4aXN0cygibW9kLmZpdHMuMnBzMiIpKSB7CiBsb2FkKGZpbGUgPSAiLi4vZGF0YS9kZXJpdmVkL21vZEZpdF9wYXJzL21vZC5maXRzLjJwcy5mbHguc3RvY2tfMjAyMC0xMi0wMi5SZGF0YSIpCn0KaWYgKCFleGlzdHMoIm1vZC5maXRzLjJwcDMiKSkgewogbG9hZChmaWxlID0gIi4uL2RhdGEvZGVyaXZlZC9tb2RGaXRfcGFycy9tb2QuZml0cy4ycHAzXzIwMjAtMTItMDguUkRhdGEiKQp9CmlmICghZXhpc3RzKCJtb2QuZml0cy4ycHMzIikpIHsKIGxvYWQoZmlsZSA9ICIuLi9kYXRhL2Rlcml2ZWQvbW9kRml0X3BhcnMvbW9kLmZpdHMuMnBzM18yMDIwLTEyLTA4LlJkYXRhIikKfQppZiAoIWV4aXN0cygibW9kLmZpdHMuMnBwM3MiKSkgewogbG9hZChmaWxlID0gIi4uL2RhdGEvZGVyaXZlZC9tb2RGaXRfcGFycy9tb2QuZml0cy4ycHAzc18yMDIwLTEyLTA4LlJEYXRhIikKfQppZiAoIWV4aXN0cygibW9kLmZpdHMuMnBzM3MiKSkgewogbG9hZChmaWxlID0gIi4uL2RhdGEvZGVyaXZlZC9tb2RGaXRfcGFycy9tb2QuZml0cy4ycHMzc18yMDIwLTEyLTA4LlJkYXRhIikKfQoKIyMgUGFyIGVzdGltYXRlcwojIDJwcApwYXJzLmZpdC4ycHAgPC0gbGFwcGx5KG1vZC5maXRzLjJwcCwgIltbIiwgMSkKbmFtZXMocGFycy5maXQuMnBwKSA8LSBuYW1lcyhwYXJzLmkuMnBwKVtpeC4xMF0KIyAycHAgZ2FtID0gWy41LCAuOTVdCnBhcnMuZml0LjJwcC5wMy41Ljk1IDwtIGxhcHBseShtb2QuZml0cy4ycHAucDMuNS45NSwgIltbIiwgMSkKbmFtZXMocGFycy5maXQuMnBwLnAzLjUuOTUpIDwtIG5hbWVzKHBhcnMuaS4ycHApW2l4LjEwXQoKIyAycHMKcGFycy5maXQuMnBzIDwtIGxhcHBseShtb2QuZml0cy4ycHMsICJbWyIsIDEpCm5hbWVzKHBhcnMuZml0LjJwcykgPC0gbmFtZXMocGFycy5pLjJwcylbaXguMTBdCgoKIyAycHAyIChpbnB1dC9zdG9jayBhbmQgMTRDIGNvbnN0cmFpbnRzKQpwYXJzLmZpdC4ycHAyIDwtIGxhcHBseShtb2QuZml0cy4ycHAyLCAiW1siLCAxKQpuYW1lcyhwYXJzLmZpdC4ycHAyKSA8LSBuYW1lcyhwYXJzLmkuMnBwKVtpeC4xMF0KIyAycHMyIChpbnB1dC9zdG9jayBhbmQgMTRDIGNvbnN0cmFpbnRzKQpwYXJzLmZpdC4ycHMyIDwtIGxhcHBseShtb2QuZml0cy4ycHMyLCAiW1siLCAxKQpuYW1lcyhwYXJzLmZpdC4ycHMyKSA8LSBuYW1lcyhwYXJzLmkuMnBzKVtpeC4xMF0KCiMgMnBwMyAoMTRDIGNvbnN0cmFpbnRzLCBjb25zdHJhaW5lZCBwYXIgcmFuZ2VzLCBzdG9jay1maXQgaW5wdXRzKQpwYXJzLmZpdC4ycHAzIDwtIGxhcHBseShtb2QuZml0cy4ycHAzLCAiW1siLCAxKQpuYW1lcyhwYXJzLmZpdC4ycHAzKSA8LSBuYW1lcyhwYXJzLmkuMnBwKVtpeC4xMF0KIyAycHMzICgxNEMgY29uc3RyYWludHMsIGNvbnN0cmFpbmVkIHBhciByYW5nZXMsIHN0b2NrLWZpdCBpbnB1dHMpCnBhcnMuZml0LjJwczMgPC0gbGFwcGx5KG1vZC5maXRzLjJwczMsICJbWyIsIDEpCm5hbWVzKHBhcnMuZml0LjJwczMpIDwtIG5hbWVzKHBhcnMuaS4ycHMpW2l4LjEwXQoKIyAycHAzcyAoMTRDIGNvbnN0cmFpbnRzLCBjb25zdHJhaW5lZCBwYXIgcmFuZ2VzLCBzdG9jay1maXQgaW5wdXRzLCArIHN0b2NrIGNvbnN0cmFpbnQpCnBhcnMuZml0LjJwcDNzIDwtIGxhcHBseShtb2QuZml0cy4ycHAzcywgIltbIiwgMSkKbmFtZXMocGFycy5maXQuMnBwM3MpIDwtIG5hbWVzKHBhcnMuaS4ycHApW2l4LjEwXQojIDJwczNzICgxNEMgY29uc3RyYWludHMsIGNvbnN0cmFpbmVkIHBhciByYW5nZXMsIHN0b2NrLWZpdCBpbnB1dHMsICsgc3RvY2sgY29uc3RyYWludCkKcGFycy5maXQuMnBzM3MgPC0gbGFwcGx5KG1vZC5maXRzLjJwczNzLCAiW1siLCAxKQpuYW1lcyhwYXJzLmZpdC4ycHMzcykgPC0gbmFtZXMocGFycy5pLjJwcylbaXguMTBdCgojIyBzdG9jayAmIGJ1bGsgMTRDIGNvc3RzIG9ubHkKIyAycHAKcGFycy5maXQuMnBwNC4xMCA8LSBsYXBwbHkobW9kLmZpdHMuMnBwNC4xMCwgIltbIiwgMSkKbmFtZXMocGFycy5maXQuMnBwNC4xMCkgPC0gbmFtZXMocGFycy5pLjJwcClbaXguMTBdCnBhcnMuZml0LjJwcDQuMzAgPC0gbGFwcGx5KG1vZC5maXRzLjJwcDQuMzAsICJbWyIsIDEpCm5hbWVzKHBhcnMuZml0LjJwcDQuMzApIDwtIG5hbWVzKHBhcnMuaS4ycHApW2l4LjMwXQojIDJwcwpwYXJzLmZpdC4ycHM0LjEwIDwtIGxhcHBseShtb2QuZml0cy4ycHM0LjEwLCAiW1siLCAxKQpuYW1lcyhwYXJzLmZpdC4ycHM0LjEwKSA8LSBuYW1lcyhwYXJzLmkuMnBzKVtpeC4xMF0KcGFycy5maXQuMnBzNC4zMCA8LSBsYXBwbHkobW9kLmZpdHMuMnBzNC4zMCwgIltbIiwgMSkKbmFtZXMocGFycy5maXQuMnBzNC4zMCkgPC0gbmFtZXMocGFycy5pLjJwcylbaXguMzBdCgojIyBzdG9jaywgYnVsayBhbmQgcmVzcGlyYXRpb24gMTRDIGNvc3RzCiMgMnBwCnBhcnMuZml0LjJwcDRyLjEwIDwtIGxhcHBseShtb2QuZml0cy4ycHA0ci4xMCwgIltbIiwgMSkKbmFtZXMocGFycy5maXQuMnBwNHIuMTApIDwtIG5hbWVzKHBhcnMuaS4ycHApW2l4LjEwXQpwYXJzLmZpdC4ycHA0ci4zMCA8LSBsYXBwbHkobW9kLmZpdHMuMnBwNHIuMzAsICJbWyIsIDEpCm5hbWVzKHBhcnMuZml0LjJwcDRyLjMwKSA8LSBuYW1lcyhwYXJzLmkuMnBwKVtpeC4zMF0KIyAycHMKcGFycy5maXQuMnBzNHIuMTAgPC0gbGFwcGx5KG1vZC5maXRzLjJwczRyLjEwLCAiW1siLCAxKQpuYW1lcyhwYXJzLmZpdC4ycHM0ci4xMCkgPC0gbmFtZXMocGFycy5pLjJwcylbaXguMTBdCnBhcnMuZml0LjJwczRyLjMwIDwtIGxhcHBseShtb2QuZml0cy4ycHM0ci4zMCwgIltbIiwgMSkKbmFtZXMocGFycy5maXQuMnBzNHIuMzApIDwtIG5hbWVzKHBhcnMuaS4ycHMpW2l4LjMwXQoKIyMgU3VtbWFyeSBvZiBmaXRzCiMgMnBwCnBhcnMuZml0LjJwcC5zdW0gPC0gbGFwcGx5KG1vZC5maXRzLjJwcCwgZnVuY3Rpb24oeCkgewogIHRyeUNhdGNoKHN1bW1hcnkoeCksIAogICAgICAgICAgIGVycm9yID0gZnVuY3Rpb24gKGUpIHtjYXQoIkVSUk9SIDoiLCBjb25kaXRpb25NZXNzYWdlKGUpLCAiXG4iKX0pCn0pCm5hbWVzKHBhcnMuZml0LjJwcC5zdW0pIDwtIG5hbWVzKHBhcnMuZml0LjJwcCkKIyAycHMKcGFycy5maXQuMnBzLnN1bSA8LSBsYXBwbHkobW9kLmZpdHMuMnBzLCBmdW5jdGlvbih4KSB7CiAgdHJ5Q2F0Y2goc3VtbWFyeSh4KSwgCiAgICAgICAgICAgZXJyb3IgPSBmdW5jdGlvbiAoZSkge2NhdCgiRVJST1IgOiIsIGNvbmRpdGlvbk1lc3NhZ2UoZSksICJcbiIpfSkKfSkKbmFtZXMocGFycy5maXQuMnBzLnN1bSkgPC0gbmFtZXMocGFycy5maXQuMnBzKQoKIyMgU3VtbWFyeSBvZiBlcnJvcnMKIyBiZXN0IHBhciBzZXQgKHNzcikKc3NyLjJwcC5kZiA8LSBkYXRhLmZyYW1lKGJpbmRfcm93cyhsYXBwbHkobW9kLmZpdHMuMnBwLCAiWyIsICJzc3IiKSwgLmlkID0gIlBNZWNvX2RlcHRoIikpCnNzci4ycHMuZGYgPC0gZGF0YS5mcmFtZShiaW5kX3Jvd3MobGFwcGx5KG1vZC5maXRzLjJwcywgIlsiLCAic3NyIiksIC5pZCA9ICJQTWVjb19kZXB0aCIpKQpzc3IuMnBwMi5kZiA8LSBkYXRhLmZyYW1lKGJpbmRfcm93cyhsYXBwbHkobW9kLmZpdHMuMnBwMiwgIlsiLCAic3NyIiksIC5pZCA9ICJQTWVjb19kZXB0aCIpKQpzc3IuMnBzMi5kZiA8LSBkYXRhLmZyYW1lKGJpbmRfcm93cyhsYXBwbHkobW9kLmZpdHMuMnBzMiwgIlsiLCAic3NyIiksIC5pZCA9ICJQTWVjb19kZXB0aCIpKQojIHN0b2NrIGFuZCBidWxrIDE0QyBjb3N0cyBvbmx5CnNzci4ycHA0LjEwLmRmIDwtIGRhdGEuZnJhbWUoYmluZF9yb3dzKGxhcHBseShtb2QuZml0cy4ycHA0LjEwLCAiWyIsICJzc3IiKSwgLmlkID0gIlBNZWNvX2RlcHRoIikpCnNzci4ycHA0LjMwLmRmIDwtIGRhdGEuZnJhbWUoYmluZF9yb3dzKGxhcHBseShtb2QuZml0cy4ycHA0LjMwLCAiWyIsICJzc3IiKSwgLmlkID0gIlBNZWNvX2RlcHRoIikpCnNzci4ycHM0LjEwLmRmIDwtIGRhdGEuZnJhbWUoYmluZF9yb3dzKGxhcHBseShtb2QuZml0cy4ycHM0LjEwLCAiWyIsICJzc3IiKSwgLmlkID0gIlBNZWNvX2RlcHRoIikpCnNzci4ycHM0LjMwLmRmIDwtIGRhdGEuZnJhbWUoYmluZF9yb3dzKGxhcHBseShtb2QuZml0cy4ycHM0LjMwLCAiWyIsICJzc3IiKSwgLmlkID0gIlBNZWNvX2RlcHRoIikpCiMgc3RvY2ssIGJ1bGsgYW5kIHJlc3AgMTRDIGNvc3RzCnNzci4ycHA0ci4xMC5kZiA8LSBkYXRhLmZyYW1lKGJpbmRfcm93cyhsYXBwbHkobW9kLmZpdHMuMnBwNHIuMTAsICJbIiwgInNzciIpLCAuaWQgPSAiUE1lY29fZGVwdGgiKSkKc3NyLjJwcDRyLjMwLmRmIDwtIGRhdGEuZnJhbWUoYmluZF9yb3dzKGxhcHBseShtb2QuZml0cy4ycHA0ci4zMCwgIlsiLCAic3NyIiksIC5pZCA9ICJQTWVjb19kZXB0aCIpKQpzc3IuMnBzNHIuMTAuZGYgPC0gZGF0YS5mcmFtZShiaW5kX3Jvd3MobGFwcGx5KG1vZC5maXRzLjJwczRyLjEwLCAiWyIsICJzc3IiKSwgLmlkID0gIlBNZWNvX2RlcHRoIikpCnNzci4ycHM0ci4zMC5kZiA8LSBkYXRhLmZyYW1lKGJpbmRfcm93cyhsYXBwbHkobW9kLmZpdHMuMnBzNHIuMzAsICJbIiwgInNzciIpLCAuaWQgPSAiUE1lY29fZGVwdGgiKSkKCiMgbWVhbiByZXNpZHVhbHMsIGJ5IHZhciAodmFyX21zKQp2YXJfbXMuZGYuZnggPC0gZnVuY3Rpb24obW9kLmZpdHMubHMsIGNvc3RzKSB7CiAgZGYgPC0gZGF0YS5mcmFtZShiaW5kX3Jvd3MobGFwcGx5KG1vZC5maXRzLmxzLCAiWyIsICJ2YXJfbXMiKSwgLmlkID0gIlBNZWNvX2RlcHRoIikpCiAgaWYgKGxlbmd0aChjb3N0cykgPT0gMiApIHsKICAgIGRmJHZhciA8LSByZXAoYygicmVzcCIsICJidWxrQyIpLCBucm93KGRmKS8yKQogIH0gZWxzZSB7CiAgICBkZiR2YXIgPC0gcmVwKGMoInJlc3AiLCAiYnVsa0MiLCAiZmx4LnN0b2NrIiksIG5yb3coZGYpLzMpCiAgfQogIGRmJHZhcl9tcyA8LSByb3VuZChkZiR2YXJfbXMsIDUpCiAgcmV0dXJuKGRmKQp9CnZhcl9tcy4ycHAuZGYgPC0gdmFyX21zLmRmLmZ4KG1vZC5maXRzLjJwcCwgYygicmVzcCIsICJidWxrQyIpKQp2YXJfbXMuMnBwLnAzLjUuOTUuZGYgPC0gdmFyX21zLmRmLmZ4KG1vZC5maXRzLjJwcC5wMy41Ljk1LCBjKCJyZXNwIiwgImJ1bGtDIikpCnZhcl9tcy4ycHMuZGYgPC0gdmFyX21zLmRmLmZ4KG1vZC5maXRzLjJwcywgYygicmVzcCIsICJidWxrQyIpKQp2YXJfbXMuMnBwMi5kZiA8LSB2YXJfbXMuZGYuZngobW9kLmZpdHMuMnBwMiwgYygicmVzcCIsICJidWxrQyIsICJmbHguc3RvY2siKSkKdmFyX21zLjJwczIuZGYgPC0gdmFyX21zLmRmLmZ4KG1vZC5maXRzLjJwczIsIGMoInJlc3AiLCAiYnVsa0MiLCAiZmx4LnN0b2NrIikpCgojIGJpbmQgZml0dGVkIHBhcnMgd2l0aCBpbml0aWFsIHBhcnMgaW50byBkYXRhIGZyYW1lIGZvciBwbG90dGluZy9zdW1tYXJpemluZwpwYXIuZml0LmRmLmZ4IDwtIGZ1bmN0aW9uKG1vZCwgcGFycy5maXQsIHBhcnMuaSkgewogIGRmIDwtIGJpbmRfcm93cygKICAgIGxhcHBseSgKICAgICAgbWFwcGx5KHJiaW5kLCAKICAgICAgICAgICAgIHBhcnMuZml0LAogICAgICAgICAgICAgcGFycy5pLAogICAgICAgICAgICAgU0lNUExJRlkgPSBGQUxTRSksIAogICAgICBmdW5jdGlvbihkZikgewogICAgICAgIGRmIDwtIGRhdGEuZnJhbWUoZGYpCiAgICAgICAgaWYgKG1vZCA9PSAiMnBwIikgewogICAgICAgICAgY29sbmFtZXMoZGYpIDwtIGMoImtmYXN0IiwgImtzbG93IiwgImdhbSIpCiAgICAgICAgfSBlbHNlIHsKICAgICAgICAgIGNvbG5hbWVzKGRmKSA8LSBjKCJrZmFzdCIsICJrc2xvdyIsICJhMjEiKQogICAgICAgIH0KICAgICAgICBkZiRlc3QgPC0gYygiZml0IiwgImluaXQiKQogICAgICAgIHJldHVybihkZikKICAgICAgfSkKICApCiAgZGYkUE1lY29fZGVwdGggPC0gcmVwKG5hbWVzKHBhcnMuaSksIGVhY2ggPSAyKQogIGRmJFBNIDwtIHN1YnN0cihkZiRQTWVjb19kZXB0aCwgc3RhcnQgPSAxLCBzdG9wID0gMikKICBkZiRlY28gPC0gc3Vic3RyKGRmJFBNZWNvX2RlcHRoLCBzdGFydCA9IDMsIHN0b3AgPSA0KQogIGRmJGRlcHRoIDwtIHN1YnN0cihkZiRQTWVjb19kZXB0aCwgc3RhcnQgPSA2LCBzdG9wID0gbGVuZ3RoKGRmJFBNZWNvX2RlcHRoKSkKICByZXR1cm4oZGYpCn0KCgojIyAycHAKIyBnYW0gcmFuZ2UgPSBbMCwgMV0KcGFycy5maXQuMnBwLmRmIDwtIHBhci5maXQuZGYuZngobW9kID0gIjJwcCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcnMuZml0ID0gcGFycy5maXQuMnBwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJzLmkgPSBwYXJzLmkuMnBwW2l4LjEwXSkKIyBnYW0gcmFuZ2UgPSBbLjUsIC45NV0KcGFycy5maXQuMnBwLnAzLjUuOTUuZGYgPC0gcGFyLmZpdC5kZi5meChtb2QgPSAiMnBwIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJzLmZpdCA9IHBhcnMuZml0LjJwcC5wMy41Ljk1LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcnMuaSA9IHBhcnMuaS4ycHBbaXguMTBdKQojIHcvIGlucHV0L3N0b2NrIGNvc3QgYW5kIGdhbSByYW5nZSA9IFsuNSwgLjk1XQpwYXJzLmZpdC4ycHAyLmRmIDwtIHBhci5maXQuZGYuZngobW9kID0gIjJwcCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJzLmZpdCA9IHBhcnMuZml0LjJwcDIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJzLmkgPSBwYXJzLmkuMnBwW2l4LjEwXSkKCiMjIDJwcwojIGEyMSByYW5nZSA9IFswLCAxXQpwYXJzLmZpdC4ycHMuZGYgPC0gcGFyLmZpdC5kZi5meChtb2QgPSAiMnBzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFycy5maXQgPSBwYXJzLmZpdC4ycHMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcnMuaSA9IHBhcnMuaS4ycHNbaXguMTBdKQojIHcvIGlucHV0L3N0b2NrIGNvc3QgYW5kIGEyMSByYW5nZSA9IFswLCAxXQpwYXJzLmZpdC4ycHMyLmRmIDwtIHBhci5maXQuZGYuZngobW9kID0gIjJwcyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcnMuZml0ID0gcGFycy5maXQuMnBzMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFycy5pID0gcGFycy5pLjJwc1tpeC4xMF0pCgojIyBDb25zdHJhaW5lZCBwYXIgcmFuZ2VzLCB3aXRoIGFuZCB3aXRob3V0IHN0b2NrIGNvbnN0cmFpbnQKIyB3L28gc3RvY2sKcGFycy5maXQuMnBwMy5kZiA8LSBwYXIuZml0LmRmLmZ4KG1vZCA9ICIycHAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFycy5maXQgPSBwYXJzLmZpdC4ycHAzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFycy5pID0gcGFycy5pLjJwcFtpeC4xMF0pCnBhcnMuZml0LjJwczMuZGYgPC0gcGFyLmZpdC5kZi5meChtb2QgPSAiMnBzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcnMuZml0ID0gcGFycy5maXQuMnBzMywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcnMuaSA9IHBhcnMuaS4ycHNbaXguMTBdKQojIHcvIHN0b2NrCnBhcnMuZml0LjJwcDNzLmRmIDwtIHBhci5maXQuZGYuZngobW9kID0gIjJwcCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFycy5maXQgPSBwYXJzLmZpdC4ycHAzcywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJzLmkgPSBwYXJzLmkuMnBzW2l4LjEwXSkKcGFycy5maXQuMnBzM3MuZGYgPC0gcGFyLmZpdC5kZi5meChtb2QgPSAiMnBzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJzLmZpdCA9IHBhcnMuZml0LjJwczNzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcnMuaSA9IHBhcnMuaS4ycHNbaXguMTBdKQojIHcvIHN0b2NrICYgYnVsayAxNEMgb25seQpwYXJzLmZpdC4ycHA0LjEwLmRmIDwtIHBhci5maXQuZGYuZngobW9kID0gIjJwcCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJzLmZpdCA9IHBhcnMuZml0LjJwcDQuMTAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJzLmkgPSBwYXJzLmkuMnBwW2l4LjEwXSkKcGFycy5maXQuMnBwNC4zMC5kZiA8LSBwYXIuZml0LmRmLmZ4KG1vZCA9ICIycHAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFycy5maXQgPSBwYXJzLmZpdC4ycHA0LjMwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFycy5pID0gcGFycy5pLjJwcFtpeC4zMF0pCnBhcnMuZml0LjJwczQuMTAuZGYgPC0gcGFyLmZpdC5kZi5meChtb2QgPSAiMnBzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcnMuZml0ID0gcGFycy5maXQuMnBzNC4xMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcnMuaSA9IHBhcnMuaS4ycHNbaXguMTBdKQpwYXJzLmZpdC4ycHM0LjMwLmRmIDwtIHBhci5maXQuZGYuZngobW9kID0gIjJwcyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJzLmZpdCA9IHBhcnMuZml0LjJwczQuMzAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJzLmkgPSBwYXJzLmkuMnBzW2l4LjMwXSkKCiMgdy8gc3RvY2ssIGJ1bGsgKyByZXNwIDE0QwpwYXJzLmZpdC4ycHA0ci4xMC5kZiA8LSBwYXIuZml0LmRmLmZ4KG1vZCA9ICIycHAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFycy5maXQgPSBwYXJzLmZpdC4ycHA0ci4xMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcnMuaSA9IHBhcnMuaS4ycHBbaXguMTBdKQpwYXJzLmZpdC4ycHA0ci4zMC5kZiA8LSBwYXIuZml0LmRmLmZ4KG1vZCA9ICIycHAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFycy5maXQgPSBwYXJzLmZpdC4ycHA0ci4zMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcnMuaSA9IHBhcnMuaS4ycHBbaXguMzBdKQpwYXJzLmZpdC4ycHM0ci4xMC5kZiA8LSBwYXIuZml0LmRmLmZ4KG1vZCA9ICIycHMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFycy5maXQgPSBwYXJzLmZpdC4ycHM0ci4xMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcnMuaSA9IHBhcnMuaS4ycHNbaXguMTBdKQpwYXJzLmZpdC4ycHM0ci4zMC5kZiA8LSBwYXIuZml0LmRmLmZ4KG1vZCA9ICIycHMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFycy5maXQgPSBwYXJzLmZpdC4ycHM0ci4zMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcnMuaSA9IHBhcnMuaS4ycHNbaXguMzBdKQoKCiMjIFN1bW1hcml6ZSBieSBQTSwgZGVwdGgKIyAycHAKIyBQTS9kZXB0aApwYXJzLmZpdC4ycHAuZGYuUE0gPC0gcGFycy5maXQuMnBwLmRmICU+JQogICAgZmlsdGVyKGVzdCA9PSAiZml0IikgJT4lCiAgICBzZWxlY3QoIWMoZXN0LCBQTWVjb19kZXB0aCwgZWNvKSkgJT4lCiAgICBncm91cF9ieShQTSwgZGVwdGgpICU+JQogICAgc3VtbWFyaXplX2FsbChsaXN0KG1lYW4gPSBtZWFuLCBzZCA9IHNkKSkgJT4lCiAgICBtdXRhdGVfaWYoaXMubnVtZXJpYywgZm9ybWF0LCBkaWdpdHMgPSAyKQojIHByaW50IHRhYmxlCmtuaXRyOjprYWJsZShwYXJzLmZpdC4ycHAuZGYuUE0sCiAgICAgICAgICAgICBjYXB0aW9uID0gIk1lYW4gcGFyYW1ldGVyIGVzdGltYXRlcyBieSBwYXJlbnQgbWF0ZXJpYWwgKFBNKSIsCiAgICAgICAgICAgICBhbGlnbiA9ICJjIikKIyBlY28vZGVwdGgKcGFycy5maXQuMnBwLmRmLmVjbyA8LSBwYXJzLmZpdC4ycHAuZGYgJT4lCiAgZmlsdGVyKGVzdCA9PSAiZml0IikgJT4lCiAgbXV0YXRlKGVjbyA9IGZhY3RvcihlY28sIGxldmVscyA9IGMoInBwIiwgIndmIiwgInJmIikpKSAlPiUKICBzZWxlY3QoIWMoZXN0LCBQTWVjb19kZXB0aCwgUE0pKSAlPiUKICBncm91cF9ieShlY28sIGRlcHRoKSAlPiUKICBzdW1tYXJpemVfYWxsKGxpc3QobWVhbiA9IG1lYW4sIHNkID0gc2QpKSAlPiUKICBtdXRhdGVfaWYoaXMubnVtZXJpYywgZm9ybWF0LCBkaWdpdHMgPSAyKQojIHByaW50IHRhYmxlCmtuaXRyOjprYWJsZShwYXJzLmZpdC4ycHAuZGYuZWNvLAogICAgICAgICAgICAgY2FwdGlvbiA9ICJNZWFuIHBhcmFtZXRlciBlc3RpbWF0ZXMgYnkgZWNvc3lzdGVtIChlY28pIiwKICAgICAgICAgICAgIGFsaWduID0gImMiKQpgYGAKCmBgYHtyIHNlbnMtZnVuLWZpdHN9CiMjIGxvb2sgYXQgc2Vuc0Z1biBvdXRwdXQKIyB3aXRob3V0IGNvbnN0cmFpbnRzCnNlbnMuMnBwIDwtIGxhcHBseShtb2Quc2Vucy5maXRzLjJwcCwgZnVuY3Rpb24oeCkgeFtbMl1dKQpzZW5zLjJwcyA8LSBsYXBwbHkobW9kLnNlbnMuZml0cy4ycHMsIGZ1bmN0aW9uKHgpIHhbWzJdXSkKIyB3aXRob3V0IHN0b2NrIGNvbnN0cmFpbnQKc2Vucy4ycHAzIDwtIGxhcHBseShtb2Quc2Vucy5maXRzLjJwcDMsIGZ1bmN0aW9uKHgpIHhbWzJdXSkKc2Vucy4ycHMzIDwtIGxhcHBseShtb2Quc2Vucy5maXRzLjJwczMsIGZ1bmN0aW9uKHgpIHhbWzJdXSkKIyB3aXRoIHN0b2NrIGNvbnN0cmFpbnQKc2Vucy4ycHAzcyA8LSBsYXBwbHkobW9kLnNlbnMuZml0cy4ycHAzcywgZnVuY3Rpb24oeCkgeFtbMl1dKQpzZW5zLjJwczNzIDwtIGxhcHBseShtb2Quc2Vucy5maXRzLjJwczNzLCBmdW5jdGlvbih4KSB4W1syXV0pCiMgd2l0aCBzdG9jayBjb25zdHJhaW50LCB3L28gcmVzcApzZW5zLjJwcDQuMTAgPC0gbGFwcGx5KG1vZC5zZW5zLmZpdHMuMnBwNC4xMCwgZnVuY3Rpb24oeCkgeFtbMl1dKQpzZW5zLjJwcDQuMzAgPC0gbGFwcGx5KG1vZC5zZW5zLmZpdHMuMnBwNC4zMCwgZnVuY3Rpb24oeCkgeFtbMl1dKQpzZW5zLjJwczQuMTAgPC0gbGFwcGx5KG1vZC5zZW5zLmZpdHMuMnBzNC4xMCwgZnVuY3Rpb24oeCkgeFtbMl1dKQpzZW5zLjJwczQuMzAgPC0gbGFwcGx5KG1vZC5zZW5zLmZpdHMuMnBzNC4zMCwgZnVuY3Rpb24oeCkgeFtbMl1dKQojIHdpdGggc3RvY2sgY29uc3RyYWludCArIHJlc3AKc2Vucy4ycHA0ci4xMCA8LSBsYXBwbHkobW9kLnNlbnMuZml0cy4ycHA0ci4xMCwgZnVuY3Rpb24oeCkgeFtbMl1dKQpzZW5zLjJwcDRyLjMwIDwtIGxhcHBseShtb2Quc2Vucy5maXRzLjJwcDRyLjMwLCBmdW5jdGlvbih4KSB4W1syXV0pCnNlbnMuMnBzNHIuMTAgPC0gbGFwcGx5KG1vZC5zZW5zLmZpdHMuMnBzNHIuMTAsIGZ1bmN0aW9uKHgpIHhbWzJdXSkKc2Vucy4ycHM0ci4zMCA8LSBsYXBwbHkobW9kLnNlbnMuZml0cy4ycHM0ci4zMCwgZnVuY3Rpb24oeCkgeFtbMl1dKQoKCiMgcGxvdCBzZW5zaXRpdml0eQojIHcvbyBjb25zdHJhaW50cwpsYXBwbHkoc2Vucy4ycHAsIGZ1bmN0aW9uKHgpIHBsb3QoeCwgd2hpY2ggPSBjKCJidWxrQyIsICJyZXNwIikpKQpsYXBwbHkoc2Vucy4ycHMsIGZ1bmN0aW9uKHgpIHBsb3QoeCwgd2hpY2ggPSBjKCJidWxrQyIsICJyZXNwIikpKQojIHcvbyBzdG9jayBjb25zdHJhaW50CmxhcHBseShzZW5zLjJwcDMsIGZ1bmN0aW9uKHgpIHBsb3QoeCwgd2hpY2ggPSBjKCJidWxrQyIsICJjU3RvY2siKSkpCmxhcHBseShzZW5zLjJwczMsIGZ1bmN0aW9uKHgpIHBsb3QoeCwgd2hpY2ggPSBjKCJidWxrQyIsICJjU3RvY2siKSkpCmxhcHBseShzZW5zLjJwcDNzLCBmdW5jdGlvbih4KSBwbG90KHgsIHdoaWNoID0gYygiYnVsa0MiLCAiY1N0b2NrIikpKQpsYXBwbHkoc2Vucy4ycHMzcywgZnVuY3Rpb24oeCkgcGxvdCh4LCB3aGljaCA9IGMoImJ1bGtDIiwgImNTdG9jayIpKSkKIyB3aXRoIHN0b2NrIGNvbnN0cmFpbnQsIHcvbyByZXNwCmxhcHBseShzZW5zLjJwcDQuMTAsIGZ1bmN0aW9uKHgpIHBsb3QoeCwgd2hpY2ggPSBjKCJidWxrQyIsICJjU3RvY2siKSkpCmxhcHBseShzZW5zLjJwcDQuMzAsIGZ1bmN0aW9uKHgpIHBsb3QoeCwgd2hpY2ggPSBjKCJidWxrQyIsICJjU3RvY2siKSkpCmxhcHBseShzZW5zLjJwczQuMTAsIGZ1bmN0aW9uKHgpIHBsb3QoeCwgd2hpY2ggPSBjKCJidWxrQyIsICJjU3RvY2siKSkpCmxhcHBseShzZW5zLjJwczQuMzAsIGZ1bmN0aW9uKHgpIHBsb3QoeCwgd2hpY2ggPSBjKCJidWxrQyIsICJjU3RvY2siKSkpCiMgd2l0aCBzdG9jayBjb25zdHJhaW50ICsgcmVzcApsYXBwbHkoc2Vucy4ycHA0ci4xMCwgZnVuY3Rpb24oeCkgcGxvdCh4LCB3aGljaCA9IGMoImJ1bGtDIiwgImNTdG9jayIpKSkKbGFwcGx5KHNlbnMuMnBwNHIuMzAsIGZ1bmN0aW9uKHgpIHBsb3QoeCwgd2hpY2ggPSBjKCJidWxrQyIsICJjU3RvY2siKSkpCmxhcHBseShzZW5zLjJwczRyLjEwLCBmdW5jdGlvbih4KSBwbG90KHgsIHdoaWNoID0gYygiYnVsa0MiLCAiY1N0b2NrIikpKQpsYXBwbHkoc2Vucy4ycHM0ci4zMCwgZnVuY3Rpb24oeCkgcGxvdCh4LCB3aGljaCA9IGMoImJ1bGtDIiwgImNTdG9jayIpKSkKCgojIGxvb2sgYXQgaWRlbnRpZmlhYmlsaXR5CmluZGVuLmRmLmZ4IDwtIGZ1bmN0aW9uKGxzLCBtb2QpIHsKICBsYXBwbHkobHMsIGZ1bmN0aW9uKHgpIHsKICAgIGRmIDwtIGNvbGxpbih4KQogICAgaWYgKG1vZCA9PSAiMnBwIikgewogICAgICBkZiRQYXJDb21ibyA8LSBmYWN0b3IoYygiazEgKyBrMiIsICJrMSArIGdhbSIsICJrMiArIGdhbSIsICJrMSArIGsyICsgZ2FtIikpCiAgICB9IGVsc2UgewogICAgICBkZiRQYXJDb21ibyA8LSBmYWN0b3IoYygiazEgKyBrMiIsICJrMSArIGEyMSIsICJrMiArIGEyMSIsICJrMSArIGsyICsgYTIxIikpCiAgICB9CiAgICByZXR1cm4oZGYpCiAgfSkKfQoKaWRlbi4ycHAgPC0gaW5kZW4uZGYuZngoc2Vucy4ycHAsIG1vZCA9ICIycHAiKQppZGVuLjJwcyA8LSBpbmRlbi5kZi5meChzZW5zLjJwcywgbW9kID0gIjJwcyIpCmlkZW4uMnBwMyA8LSBpbmRlbi5kZi5meChzZW5zLjJwcDMsIG1vZCA9ICIycHAiKQppZGVuLjJwczMgPC0gaW5kZW4uZGYuZngoc2Vucy4ycHMzLCBtb2QgPSAiMnBzIikKaWRlbi4ycHAzcyA8LSBpbmRlbi5kZi5meChzZW5zLjJwcDNzLCBtb2QgPSAiMnBwIikKaWRlbi4ycHMzcyA8LSBpbmRlbi5kZi5meChzZW5zLjJwczNzLCBtb2QgPSAiMnBzIikKIyB3aXRoIHN0b2NrIGNvbnN0cmFpbnQsIHcvbyByZXNwCmlkZW4uMnBwNC4xMCA8LSBpbmRlbi5kZi5meChzZW5zLjJwcDQuMTAsIG1vZCA9ICIycHAiKQppZGVuLjJwcDQuMzAgPC0gaW5kZW4uZGYuZngoc2Vucy4ycHA0LjMwLCBtb2QgPSAiMnBwIikKaWRlbi4ycHM0LjEwIDwtIGluZGVuLmRmLmZ4KHNlbnMuMnBzNC4xMCwgbW9kID0gIjJwcyIpCmlkZW4uMnBzNC4zMCA8LSBpbmRlbi5kZi5meChzZW5zLjJwczQuMzAsIG1vZCA9ICIycHMiKQojIHdpdGggc3RvY2sgY29uc3RyYWludCArIHJlc3AKaWRlbi4ycHA0ci4xMCA8LSBpbmRlbi5kZi5meChzZW5zLjJwcDRyLjEwLCBtb2QgPSAiMnBwIikKaWRlbi4ycHA0ci4zMCA8LSBpbmRlbi5kZi5meChzZW5zLjJwcDRyLjMwLCBtb2QgPSAiMnBwIikKaWRlbi4ycHM0ci4xMCA8LSBpbmRlbi5kZi5meChzZW5zLjJwczRyLjEwLCBtb2QgPSAiMnBzIikKaWRlbi4ycHM0ci4zMCA8LSBpbmRlbi5kZi5meChzZW5zLjJwczRyLjMwLCBtb2QgPSAiMnBzIikKCiMgaWRlbnRpZmlhYmlsaXR5IHBsb3QgZnVuY3Rpb24KY29sbC5wbG90LmZ4IDwtIGZ1bmN0aW9uKGRmLCBtb2QsIFBNZWNvX2RlcHRoLCBjb2wubWF4KSB7CiAgZ2dwbG90KGRmLCBhZXMoTiwgbG9nKGNvbGxpbmVhcml0eSksIGNvbG9yID0gUGFyQ29tYm8pKSArCiAgICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSBsb2coMjApKSArCiAgICBnZW9tX3BvaW50KHNpemUgPSAzLjUsIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAuMSkpICsKICAgIHNjYWxlX3lfY29udGludW91cyhsaW1pdHMgPSBjKDAsIGxvZyhjb2wubWF4KSkpICsKICAgIHNjYWxlX3hfY29udGludW91cyhsaW1pdHMgPSBjKDEuNSwgMy41KSwgYnJlYWtzID0gYygyLCAzKSkgKwogICAgbGFicyh0aXRsZSA9IHBhc3RlKFBNZWNvX2RlcHRoLCBtb2QpKSArCiAgICB0aGVtZV9idygpICsKICAgIHRoZW1lKHBhbmVsLmdyaWQgPSBlbGVtZW50X2JsYW5rKCkpICsKICAgIGlmIChtb2QgPT0gIjJwcCIgfCBtb2QgPT0gIjJwcCArIHN0b2NrIikgewogICAgIHNjYWxlX2NvbG9yX21hbnVhbCgKICAgICAgIG5hbWUgPSAiUGFyYW1ldGVyIGNvbWJpbmF0aW9uIiwKICAgICAgIHZhbHVlcyA9IGMoImsxICsgazIiID0gIiNFRjQ3NkYiLAogICAgICAgICAgICAgICAgICAiazEgKyBnYW0iID0gIiNGRkQxNjYiLAogICAgICAgICAgICAgICAgICAiazIgKyBnYW0iID0gIiMxMThBQjIiLAogICAgICAgICAgICAgICAgICAiazEgKyBrMiArIGdhbSIgPSAiMDczQjRDIikpIAogICAgfSBlbHNlIHsKICAgICAgc2NhbGVfY29sb3JfbWFudWFsKAogICAgICAgIG5hbWUgPSAiUGFyYW1ldGVyIGNvbWJpbmF0aW9uIiwKICAgICAgICB2YWx1ZXMgPSBjKCJrMSArIGsyIiA9ICIjRUY0NzZGIiwKICAgICAgICAgICAgICAgICAgImsxICsgYTIxIiA9ICIjRkZEMTY2IiwKICAgICAgICAgICAgICAgICAgImsyICsgYTIxIiA9ICIjMTE4QUIyIiwKICAgICAgICAgICAgICAgICAgImsxICsgazIgKyBhMjEiID0gIjA3M0I0QyIpKQogICAgfQp9CmxhcHBseShzZXFfYWxvbmcoaWRlbi4ycHApLCBmdW5jdGlvbihpKSB7CiAgY29sbC5wbG90LmZ4KGlkZW4uMnBwW1tpXV0sIG1vZCA9ICIycHAiLCBuYW1lcyhpZGVuLjJwcClbaV0sIG1heChpZGVuLjJwcFtbaV1dWyJjb2xsaW5lYXJpdHkiXSkpCn0pCmxhcHBseShzZXFfYWxvbmcoaWRlbi4ycHMpLCBmdW5jdGlvbihpKSB7CiAgY29sbC5wbG90LmZ4KGlkZW4uMnBzW1tpXV0sIG1vZCA9ICIycHMiLCBuYW1lcyhpZGVuLjJwcylbaV0sIG1heChpZGVuLjJwc1tbaV1dWyJjb2xsaW5lYXJpdHkiXSkpCn0pCmxhcHBseShzZXFfYWxvbmcoaWRlbi4ycHAzKSwgZnVuY3Rpb24oaSkgewogIGNvbGwucGxvdC5meChpZGVuLjJwcDNbW2ldXSwgbW9kID0gIjJwcCIsIG5hbWVzKGlkZW4uMnBwMylbaV0pCn0pCmxhcHBseShzZXFfYWxvbmcoaWRlbi4ycHAzcyksIGZ1bmN0aW9uKGkpIHsKICBjb2xsLnBsb3QuZngoaWRlbi4ycHAzc1tbaV1dLCBtb2QgPSAiMnBwICsgc3RvY2siLCBuYW1lcyhpZGVuLjJwcDNzKVtpXSkKfSkKbGFwcGx5KHNlcV9hbG9uZyhpZGVuLjJwczMpLCBmdW5jdGlvbihpKSB7CiAgY29sbC5wbG90LmZ4KGlkZW4uMnBzM1tbaV1dLCBtb2QgPSAiMnBzIiwgbmFtZXMoaWRlbi4ycHMzKVtpXSkKfSkKbGFwcGx5KHNlcV9hbG9uZyhpZGVuLjJwczNzKSwgZnVuY3Rpb24oaSkgewogIGNvbGwucGxvdC5meChpZGVuLjJwczNzW1tpXV0sIG1vZCA9ICIycHMgKyBzdG9jayIsIG5hbWVzKGlkZW4uMnBzM3MpW2ldKQp9KQojIHN0b2NrIGNvbnN0cmFpbnQsIHcvbyByZXNwCmNvbC5tYXggPC0gbWF4KHVubGlzdChsaXN0KGxhcHBseShpZGVuLjJwczQuMTAsIGZ1bmN0aW9uKGRmKSBkZltbImNvbGxpbmVhcml0eSJdXSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhcHBseShpZGVuLjJwczQuMzAsIGZ1bmN0aW9uKGRmKSBkZltbImNvbGxpbmVhcml0eSJdXSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhcHBseShpZGVuLjJwcDQuMTAsIGZ1bmN0aW9uKGRmKSBkZltbImNvbGxpbmVhcml0eSJdXSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhcHBseShpZGVuLjJwcDQuMzAsIGZ1bmN0aW9uKGRmKSBkZltbImNvbGxpbmVhcml0eSJdXSkpKSkKbGFwcGx5KHNlcV9hbG9uZyhpZGVuLjJwczQuMTApLCBmdW5jdGlvbihpKSB7CiAgY29sbC5wbG90LmZ4KGlkZW4uMnBzNC4xMFtbaV1dLCBtb2QgPSAiMnBzICsgc3RvY2siLCBuYW1lcyhpZGVuLjJwczQuMTApW2ldLCBjb2wubWF4KQp9KQpsYXBwbHkoc2VxX2Fsb25nKGlkZW4uMnBzNC4zMCksIGZ1bmN0aW9uKGkpIHsKICBjb2xsLnBsb3QuZngoaWRlbi4ycHM0LjMwW1tpXV0sIG1vZCA9ICIycHMgKyBzdG9jayIsIG5hbWVzKGlkZW4uMnBzNC4zMClbaV0sIGNvbC5tYXgpCn0pCmxhcHBseShzZXFfYWxvbmcoaWRlbi4ycHA0LjEwKSwgZnVuY3Rpb24oaSkgewogIGNvbGwucGxvdC5meChpZGVuLjJwcDQuMTBbW2ldXSwgbW9kID0gIjJwcCArIHN0b2NrIiwgbmFtZXMoaWRlbi4ycHA0LjEwKVtpXSwgY29sLm1heCkKfSkKbGFwcGx5KHNlcV9hbG9uZyhpZGVuLjJwcDQuMzApLCBmdW5jdGlvbihpKSB7CiAgY29sbC5wbG90LmZ4KGlkZW4uMnBwNC4zMFtbaV1dLCBtb2QgPSAiMnBwICsgc3RvY2siLCBuYW1lcyhpZGVuLjJwcDQuMzApW2ldLCBjb2wubWF4KQp9KQoKIyBzdG9jayBjb25zdHJhaW50ICsgcmVzcApjb2wubWF4LnIgPC0gbWF4KHVubGlzdChsaXN0KGxhcHBseShpZGVuLjJwczRyLjEwLCBmdW5jdGlvbihkZikgZGZbWyJjb2xsaW5lYXJpdHkiXV0pLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhcHBseShpZGVuLjJwczRyLjMwLCBmdW5jdGlvbihkZikgZGZbWyJjb2xsaW5lYXJpdHkiXV0pLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhcHBseShpZGVuLjJwcDRyLjEwLCBmdW5jdGlvbihkZikgZGZbWyJjb2xsaW5lYXJpdHkiXV0pLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhcHBseShpZGVuLjJwcDRyLjMwLCBmdW5jdGlvbihkZikgZGZbWyJjb2xsaW5lYXJpdHkiXV0pKSkpCmxhcHBseShzZXFfYWxvbmcoaWRlbi4ycHA0ci4xMCksIGZ1bmN0aW9uKGkpIHsKICBjb2xsLnBsb3QuZngoaWRlbi4ycHA0ci4xMFtbaV1dLCBtb2QgPSAiMnBwIiwgbmFtZXMoaWRlbi4ycHA0ci4xMClbaV0sIGNvbC5tYXgpCn0pCmxhcHBseShzZXFfYWxvbmcoaWRlbi4ycHA0ci4zMCksIGZ1bmN0aW9uKGkpIHsKICBjb2xsLnBsb3QuZngoaWRlbi4ycHA0ci4zMFtbaV1dLCBtb2QgPSAiMnBzIiwgbmFtZXMoaWRlbi4ycHA0ci4zMClbaV0sIGNvbC5tYXgpCn0pCmxhcHBseShzZXFfYWxvbmcoaWRlbi4ycHM0ci4xMCksIGZ1bmN0aW9uKGkpIHsKICBjb2xsLnBsb3QuZngoaWRlbi4ycHM0ci4xMFtbaV1dLCBtb2QgPSAiMnBzICsgc3RvY2siLCBuYW1lcyhpZGVuLjJwczRyLjEwKVtpXSwgY29sLm1heCkKfSkKbGFwcGx5KHNlcV9hbG9uZyhpZGVuLjJwczRyLjMwKSwgZnVuY3Rpb24oaSkgewogIGNvbGwucGxvdC5meChpZGVuLjJwczRyLjMwW1tpXV0sIG1vZCA9ICIycHMgKyBzdG9jayIsIG5hbWVzKGlkZW4uMnBzNHIuMzApW2ldLCBjb2wubWF4KQp9KQpgYGAKCgpgYGB7ciBwbG90LW1vZEZpdC1wYXJzfQojIyBwbG90IHBhcnMKcGFyLnBsb3QuZnggPC0gZnVuY3Rpb24obW9kLCBkZXB0aCwgcGFyLmRmLCBpbml0aWFsID0gRkFMU0UpIHsKICBwYXIuZGYgJT4lCiAgICB7IGlmIChpbml0aWFsID09IFRSVUUpIC4gZWxzZSBmaWx0ZXIoLiwgZXN0ID09ICJmaXQiKSB9ICU+JQogICAgZmlsdGVyKGRlcHRoID09IGRlcHRoKSAlPiUKICAgIHBpdm90X2xvbmdlcighKGVzdDpkZXB0aCksIG5hbWVzX3RvID0gInBhciIsIHZhbHVlc190byA9ICJ2YWx1ZSIpICU+JQogICAgbXV0YXRlKFBNID0gZmFjdG9yKFBNKSwKICAgICAgICAgICBlY28gPSBmYWN0b3IoZWNvLCBsZXZlbHMgPSBjKCJwcCIsICJ3ZiIsICJyZiIpKSkgJT4lCiAgICBnZ3Bsb3QoLiwgYWVzKHBhciwgdmFsdWUsIGNvbG9yID0gUE0sIHNoYXBlID0gZWNvKSkgKwogICAgIyBnZW9tX2ppdHRlcihzaXplID0gNCkgKwogICAgZ2VvbV9wb2ludChzaXplID0gNCwgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IC41KSkgKwogICAgc2NhbGVfY29sb3JfbWFudWFsKG5hbWUgPSAicGFyZW50IG1hdGVyaWFsIiwKICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIkFOIiA9ICJhbmRlc2l0ZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJCUyIgPSAiYmFzYWx0IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkdSIiA9ICJncmFuaXRlIiksCiAgICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSBjKCJBTiIgPSAiYmx1ZSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQlMiID0gInJlZCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiR1IiID0gImRhcmtncmF5IikpICsKICAgIGZhY2V0X3dyYXAoLiB+IHBhciwgc2NhbGVzID0gImZyZWUiKSArCiAgICBnZ3RpdGxlKHBhc3RlMCgibW9kRml0IHBhcnMgIiwgbW9kLCAiICIsIGRlcHRoKSkgKwogICAgdGhlbWVfYncoKSArCiAgICB0aGVtZShwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpKQp9CiMgMC0xMAojIDJwcApwYXIucGxvdC5meChtb2QgPSAiMnBwIiwKICAgICAgICAgICAgZGVwdGggPSAiMC0xMCIsCiAgICAgICAgICAgIHBhci5kZiA9IHBhcnMuZml0LjJwcC5kZiwKICAgICAgICAgICAgaW5pdGlhbCA9IEZBTFNFKQojIDJwcCwgZ2FtID0gWy41LC45NV0KcGFyLnBsb3QuZngobW9kID0gIjJwcCAoZ2FtID0gWzAuNSwgMC45NV0pIiwKICAgICAgICAgICAgZGVwdGggPSAiMC0xMCIsCiAgICAgICAgICAgIHBhci5kZiA9IHBhcnMuZml0LjJwcC5wMy41Ljk1LmRmLAogICAgICAgICAgICBpbml0aWFsID0gRkFMU0UpCiMgMnBwMgpwYXIucGxvdC5meChtb2QgPSAiMnBwMiIsCiAgICAgICAgICAgIGRlcHRoID0gIjAtMTAiLAogICAgICAgICAgICBwYXIuZGYgPSBwYXJzLmZpdC4ycHAyLmRmLAogICAgICAgICAgICBpbml0aWFsID0gRkFMU0UpCiMgMnBzCnBhci5wbG90LmZ4KG1vZCA9ICIycHMiLAogICAgICAgICAgICBkZXB0aCA9ICIwLTEwIiwKICAgICAgICAgICAgcGFyLmRmID0gcGFycy5maXQuMnBzLmRmLAogICAgICAgICAgICBpbml0aWFsID0gRkFMU0UpCiMgMnBzMgpwYXIucGxvdC5meChtb2QgPSAiMnBzMiIsCiAgICAgICAgICAgIGRlcHRoID0gIjAtMTAiLAogICAgICAgICAgICBwYXIuZGYgPSBwYXJzLmZpdC4ycHMyLmRmLAogICAgICAgICAgICBpbml0aWFsID0gRkFMU0UpCgojIHcvIGFuZCB3L28gc3RvY2sgY29uc3RyYWludApwYXIucGxvdC5meChtb2QgPSAiMnBwMyIsCiAgICAgICAgICAgIGRlcHRoID0gIjAtMTAiLAogICAgICAgICAgICBwYXIuZGYgPSBwYXJzLmZpdC4ycHAzLmRmLAogICAgICAgICAgICBpbml0aWFsID0gRkFMU0UpCnBhci5wbG90LmZ4KG1vZCA9ICIycHAzcyIsCiAgICAgICAgICAgIGRlcHRoID0gIjAtMTAiLAogICAgICAgICAgICBwYXIuZGYgPSBwYXJzLmZpdC4ycHAzcy5kZiwKICAgICAgICAgICAgaW5pdGlhbCA9IEZBTFNFKQpwYXIucGxvdC5meChtb2QgPSAiMnBzMyIsCiAgICAgICAgICAgIGRlcHRoID0gIjAtMTAiLAogICAgICAgICAgICBwYXIuZGYgPSBwYXJzLmZpdC4ycHMzLmRmLAogICAgICAgICAgICBpbml0aWFsID0gRkFMU0UpCnBhci5wbG90LmZ4KG1vZCA9ICIycHMzcyIsCiAgICAgICAgICAgIGRlcHRoID0gIjAtMTAiLAogICAgICAgICAgICBwYXIuZGYgPSBwYXJzLmZpdC4ycHMzcy5kZiwKICAgICAgICAgICAgaW5pdGlhbCA9IEZBTFNFKQoKIyMgZmx1eCBlc3QgaW5wdXRzIGJ5IGVjbwojIHN0b2NrIGFuZCBidWxrIDE0QyBvbmx5CnBhci5wbG90LmZ4KG1vZCA9ICIycHA0IiwKICAgICAgICAgICAgZGVwdGggPSAiMC0xMCIsCiAgICAgICAgICAgIHBhci5kZiA9IHBhcnMuZml0LjJwcDQuMTAuZGYsCiAgICAgICAgICAgIGluaXRpYWwgPSBGQUxTRSkKcGFyLnBsb3QuZngobW9kID0gIjJwcDQiLAogICAgICAgICAgICBkZXB0aCA9ICIyMC0zMCIsCiAgICAgICAgICAgIHBhci5kZiA9IHBhcnMuZml0LjJwcDQuMzAuZGYsCiAgICAgICAgICAgIGluaXRpYWwgPSBGQUxTRSkKcGFyLnBsb3QuZngobW9kID0gIjJwczQiLAogICAgICAgICAgICBkZXB0aCA9ICIwLTEwIiwKICAgICAgICAgICAgcGFyLmRmID0gcGFycy5maXQuMnBzNC4xMC5kZiwKICAgICAgICAgICAgaW5pdGlhbCA9IEZBTFNFKQpwYXIucGxvdC5meChtb2QgPSAiMnBzNCIsCiAgICAgICAgICAgIGRlcHRoID0gIjIwLTMwIiwKICAgICAgICAgICAgcGFyLmRmID0gcGFycy5maXQuMnBzNC4zMC5kZiwKICAgICAgICAgICAgaW5pdGlhbCA9IEZBTFNFKQoKIyBzdG9jayBhbmQgYnVsayArIHJlc3AgMTRDCnBhci5wbG90LmZ4KG1vZCA9ICIycHA0ciIsCiAgICAgICAgICAgIGRlcHRoID0gIjAtMTAiLAogICAgICAgICAgICBwYXIuZGYgPSBwYXJzLmZpdC4ycHA0ci4xMC5kZiwKICAgICAgICAgICAgaW5pdGlhbCA9IEZBTFNFKQpwYXIucGxvdC5meChtb2QgPSAiMnBwNHIiLAogICAgICAgICAgICBkZXB0aCA9ICIyMC0zMCIsCiAgICAgICAgICAgIHBhci5kZiA9IHBhcnMuZml0LjJwcDRyLjMwLmRmLAogICAgICAgICAgICBpbml0aWFsID0gRkFMU0UpCnBhci5wbG90LmZ4KG1vZCA9ICIycHM0ciIsCiAgICAgICAgICAgIGRlcHRoID0gIjAtMTAiLAogICAgICAgICAgICBwYXIuZGYgPSBwYXJzLmZpdC4ycHM0ci4xMC5kZiwKICAgICAgICAgICAgaW5pdGlhbCA9IEZBTFNFKQpwYXIucGxvdC5meChtb2QgPSAiMnBzNHIiLAogICAgICAgICAgICBkZXB0aCA9ICIyMC0zMCIsCiAgICAgICAgICAgIHBhci5kZiA9IHBhcnMuZml0LjJwczRyLjMwLmRmLAogICAgICAgICAgICBpbml0aWFsID0gRkFMU0UpCmBgYAoKYGBge3IgZml0LXNvYy1pbn0KIyMgRmluZCBiZXN0IGlucHV0cwojIDJwcAppbi5maXQuMnBwIDwtIGxhcHBseShzZXFfYWxvbmcocGFycy5maXQuMnBwKSwgZnVuY3Rpb24oaSkgewogIFBNZWNvX2RlcHRoIDwtIG5hbWVzKHBhcnMuZml0LjJwcClbaV0KICBTT0MgPC0gY3NvYy4xOS4wXzMwW1tQTWVjb19kZXB0aF1dWyAsImx5cl9zb2MiXQogIHJldHVybihpbi5maXQuZngoIjJwcCIsIHBhcnMuZml0LjJwcFtbaV1dLCBpbi5pW2l4LjEwXVtbaV1dLCBTT0MpKQp9KQpuYW1lcyhpbi5maXQuMnBwKSA8LSBuYW1lcyhtb2QuZml0cy4ycHApCiMgMnBwIGdhbSA9IFsuNSwgLjk1XQppbi5maXQuMnBwLnAzLjUuOTUgPC0gbGFwcGx5KHNlcV9hbG9uZyhwYXJzLmZpdC4ycHAucDMuNS45NSksIGZ1bmN0aW9uKGkpIHsKICBQTWVjb19kZXB0aCA8LSBuYW1lcyhwYXJzLmZpdC4ycHAucDMuNS45NSlbaV0KICBTT0MgPC0gY3NvYy4xOS4wXzMwW1tQTWVjb19kZXB0aF1dWyAsImx5cl9zb2MiXQogIHJldHVybihpbi5maXQuZngoIjJwcCIsIHBhcnMuZml0LjJwcC5wMy41Ljk1W1tpXV0sIGluLmlbaXguMTBdW1tpXV0sIFNPQykpCn0pCm5hbWVzKGluLmZpdC4ycHAucDMuNS45NSkgPC0gbmFtZXMobW9kLmZpdHMuMnBwLnAzLjUuOTUpCiMgMnBwMgppbi5maXQuMnBwMiA8LSBsYXBwbHkoc2VxX2Fsb25nKHBhcnMuZml0LjJwcDIpLCBmdW5jdGlvbihpKSB7CiAgUE1lY29fZGVwdGggPC0gbmFtZXMocGFycy5maXQuMnBwMilbaV0KICBTT0MgPC0gY3NvYy4xOS4wXzMwW1tQTWVjb19kZXB0aF1dWyAsImx5cl9zb2MiXQogIHJldHVybihpbi5maXQuZngoIjJwcCIsIHBhcnMuZml0LjJwcDJbW2ldXSwgaW4uZmx4LnN0b2NrW1tpXV0sIFNPQykpCn0pCm5hbWVzKGluLmZpdC4ycHAyKSA8LSBuYW1lcyhtb2QuZml0cy4ycHAyKQojIDJwcwppbi5maXQuMnBzIDwtIGxhcHBseShzZXFfYWxvbmcocGFycy5maXQuMnBzKSwgZnVuY3Rpb24oaSkgewogIFBNZWNvX2RlcHRoIDwtIG5hbWVzKHBhcnMuZml0LjJwcylbaV0KICBTT0MgPC0gY3NvYy4xOS4wXzMwW1tQTWVjb19kZXB0aF1dWyAsImx5cl9zb2MiXQogIHJldHVybihpbi5maXQuZngoIjJwcyIsIHBhcnMuZml0LjJwc1tbaV1dLCBpbi5pW2l4LjEwXVtbaV1dLCBTT0MpKQp9KQpuYW1lcyhpbi5maXQuMnBzKSA8LSBuYW1lcyhtb2QuZml0cy4ycHMpCiMgMnBzMgppbi5maXQuMnBzMiA8LSBsYXBwbHkoc2VxX2Fsb25nKHBhcnMuZml0LjJwczIpLCBmdW5jdGlvbihpKSB7CiAgUE1lY29fZGVwdGggPC0gbmFtZXMocGFycy5maXQuMnBzMilbaV0KICBTT0MgPC0gY3NvYy4xOS4wXzMwW1tQTWVjb19kZXB0aF1dWyAsImx5cl9zb2MiXQogIHJldHVybihpbi5maXQuZngoIjJwcyIsIHBhcnMuZml0LjJwczJbW2ldXSwgaW4uZmx4LnN0b2NrW1tpXV0sIFNPQykpCn0pCm5hbWVzKGluLmZpdC4ycHMyKSA8LSBuYW1lcyhtb2QuZml0cy4ycHMyKQoKIyMgQ2FsYyBtb2RlbGVkIHN0b2NrcyBhbmQgY29tcGFyZSB3aXRoIG1lYXN1cmVkIHN0b2NrcwojIDJwcAptb2Quc29jcy4ycHAubHMgPC0gbGFwcGx5KHNlcV9hbG9uZyhwYXJzLmZpdC4ycHApLCBmdW5jdGlvbihpKSB7CiAgc29jLmZ4KCIycHAiLCBwYXJzLmZpdC4ycHBbW2ldXSwgaW4uZml0LjJwcFtbaV1dKQp9KQpuYW1lcyhtb2Quc29jcy4ycHAubHMpIDwtIG5hbWVzKHBhcnMuZml0LjJwcCkKc29jcy4ycHAubHMgPC0gbWFwcGx5KGNiaW5kLAogICAgICAgICAgICAgICAgICAgICAgY3NvYy4xOS4wXzMwW2l4LjEwXSwgCiAgICAgICAgICAgICAgICAgICAgICBsYXBwbHkobW9kLnNvY3MuMnBwLmxzLCBjb2xTdW1zKSwgCiAgICAgICAgICAgICAgICAgICAgICBTSU1QTElGWSA9IEZBTFNFKQojIDJwcCBnYW0gPSBbLjUsIC45NV0KbW9kLnNvY3MuMnBwLnAzLjUuOTUubHMgPC0gbGFwcGx5KHNlcV9hbG9uZyhwYXJzLmZpdC4ycHAucDMuNS45NSksIGZ1bmN0aW9uKGkpIHsKICBzb2MuZngoIjJwcCIsIHBhcnMuZml0LjJwcC5wMy41Ljk1W1tpXV0sIGluLmZpdC4ycHAucDMuNS45NVtbaV1dKQp9KQpuYW1lcyhtb2Quc29jcy4ycHAucDMuNS45NS5scykgPC0gbmFtZXMocGFycy5maXQuMnBwLnAzLjUuOTUpCnNvY3MuMnBwLnAzLjUuOTVscyA8LSBtYXBwbHkoY2JpbmQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY3NvYy4xOS4wXzMwW2l4LjEwXSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFwcGx5KG1vZC5zb2NzLjJwcC5wMy41Ljk1LmxzLCBjb2xTdW1zKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgU0lNUExJRlkgPSBGQUxTRSkKIyAycHAyCm1vZC5zb2NzLjJwcDIubHMgPC0gbGFwcGx5KHNlcV9hbG9uZyhwYXJzLmZpdC4ycHAyKSwgZnVuY3Rpb24oaSkgewogIHNvYy5meCgiMnBwIiwgcGFycy5maXQuMnBwMltbaV1dLCBpbi5maXQuMnBwMltbaV1dKQp9KQpuYW1lcyhtb2Quc29jcy4ycHAyLmxzKSA8LSBuYW1lcyhwYXJzLmZpdC4ycHAyKQoKIyAycHMKbW9kLnNvY3MuMnBzLmxzIDwtIGxhcHBseShzZXFfYWxvbmcocGFycy5maXQuMnBzKSwgZnVuY3Rpb24oaSkgewogIHNvYy5meCgiMnBzIiwgcGFycy5maXQuMnBzW1tpXV0sIGluLmZpdC4ycHNbW2ldXSkKfSkKbmFtZXMobW9kLnNvY3MuMnBzLmxzKSA8LSBuYW1lcyhwYXJzLmZpdC4ycHMpCnNvY3MuMnBzLmxzIDwtIG1hcHBseShjYmluZCwKICAgICAgICAgICAgICAgICAgICAgIGNzb2MuMTkuMF8zMFtpeC4xMF0sIAogICAgICAgICAgICAgICAgICAgICAgbGFwcGx5KG1vZC5zb2NzLjJwcy5scywgY29sU3VtcyksIAogICAgICAgICAgICAgICAgICAgICAgU0lNUExJRlkgPSBGQUxTRSkKIyAycHMyCm1vZC5zb2NzLjJwczIubHMgPC0gbGFwcGx5KHNlcV9hbG9uZyhwYXJzLmZpdC4ycHMyKSwgZnVuY3Rpb24oaSkgewogIHNvYy5meCgiMnBzIiwgcGFycy5maXQuMnBzMltbaV1dLCBpbi5maXQuMnBzMltbaV1dKQp9KQpuYW1lcyhtb2Quc29jcy4ycHMyLmxzKSA8LSBuYW1lcyhwYXJzLmZpdC4ycHMyKQoKIyMgc3RvY2sgYW5kIGJ1bGsgMTRDIGNvc3RzIG9ubHkKIyAycHAKbW9kLnNvY3MuMnBwNC4xMC5scyA8LSBsYXBwbHkoc2VxX2Fsb25nKHBhcnMuZml0LjJwcDQuMTApLCBmdW5jdGlvbihpKSB7CiAgc29jLmZ4KCIycHAiLCBwYXJzLmZpdC4ycHA0LjEwW1tpXV0sIGluLmVzdFtpeC4xMF1bW2ldXSkKfSkKbmFtZXMobW9kLnNvY3MuMnBwNC4xMC5scykgPC0gbmFtZXMocGFycy5maXQuMnBwNC4xMCkKbW9kLnNvY3MuMnBwNC4zMC5scyA8LSBsYXBwbHkoc2VxX2Fsb25nKHBhcnMuZml0LjJwcDQuMzApLCBmdW5jdGlvbihpKSB7CiAgc29jLmZ4KCIycHAiLCBwYXJzLmZpdC4ycHA0LjMwW1tpXV0sIGluLmVzdFtpeC4zMF1bW2ldXSkKfSkKbmFtZXMobW9kLnNvY3MuMnBwNC4zMC5scykgPC0gbmFtZXMocGFycy5maXQuMnBwNC4zMCkKIyAycHMKbW9kLnNvY3MuMnBzNC4xMC5scyA8LSBsYXBwbHkoc2VxX2Fsb25nKHBhcnMuZml0LjJwczQuMTApLCBmdW5jdGlvbihpKSB7CiAgc29jLmZ4KCIycHMiLCBwYXJzLmZpdC4ycHM0LjEwW1tpXV0sIGluLmVzdFtpeC4xMF1bW2ldXSkKfSkKbmFtZXMobW9kLnNvY3MuMnBzNC4xMC5scykgPC0gbmFtZXMocGFycy5maXQuMnBzNC4xMCkKbW9kLnNvY3MuMnBzNC4zMC5scyA8LSBsYXBwbHkoc2VxX2Fsb25nKHBhcnMuZml0LjJwczQuMzApLCBmdW5jdGlvbihpKSB7CiAgc29jLmZ4KCIycHMiLCBwYXJzLmZpdC4ycHM0LjMwW1tpXV0sIGluLmVzdFtpeC4zMF1bW2ldXSkKfSkKbmFtZXMobW9kLnNvY3MuMnBzNC4zMC5scykgPC0gbmFtZXMocGFycy5maXQuMnBzNC4zMCkKCiMjIHN0b2NrIGFuZCBidWxrICsgcmVzcCAxNEMgY29zdHMKIyAycHAKbW9kLnNvY3MuMnBwNHIuMTAubHMgPC0gbGFwcGx5KHNlcV9hbG9uZyhwYXJzLmZpdC4ycHA0ci4xMCksIGZ1bmN0aW9uKGkpIHsKICBzb2MuZngoIjJwcCIsIHBhcnMuZml0LjJwcDRyLjEwW1tpXV0sIGluLmVzdFtpeC4xMF1bW2ldXSkKfSkKbmFtZXMobW9kLnNvY3MuMnBwNHIuMTAubHMpIDwtIG5hbWVzKHBhcnMuZml0LjJwcDRyLjEwKQptb2Quc29jcy4ycHA0ci4zMC5scyA8LSBsYXBwbHkoc2VxX2Fsb25nKHBhcnMuZml0LjJwcDRyLjMwKSwgZnVuY3Rpb24oaSkgewogIHNvYy5meCgiMnBwIiwgcGFycy5maXQuMnBwNHIuMzBbW2ldXSwgaW4uZXN0W2l4LjMwXVtbaV1dKQp9KQpuYW1lcyhtb2Quc29jcy4ycHA0ci4zMC5scykgPC0gbmFtZXMocGFycy5maXQuMnBwNHIuMzApCiMgMnBzCm1vZC5zb2NzLjJwczRyLjEwLmxzIDwtIGxhcHBseShzZXFfYWxvbmcocGFycy5maXQuMnBzNHIuMTApLCBmdW5jdGlvbihpKSB7CiAgc29jLmZ4KCIycHMiLCBwYXJzLmZpdC4ycHM0ci4xMFtbaV1dLCBpbi5lc3RbaXguMTBdW1tpXV0pCn0pCm5hbWVzKG1vZC5zb2NzLjJwczRyLjEwLmxzKSA8LSBuYW1lcyhwYXJzLmZpdC4ycHM0ci4xMCkKbW9kLnNvY3MuMnBzNHIuMzAubHMgPC0gbGFwcGx5KHNlcV9hbG9uZyhwYXJzLmZpdC4ycHM0ci4zMCksIGZ1bmN0aW9uKGkpIHsKICBzb2MuZngoIjJwcyIsIHBhcnMuZml0LjJwczRyLjMwW1tpXV0sIGluLmVzdFtpeC4zMF1bW2ldXSkKfSkKbmFtZXMobW9kLnNvY3MuMnBzNHIuMzAubHMpIDwtIG5hbWVzKHBhcnMuZml0LjJwczRyLjMwKQoKCiMjIFJldHVybiBkYXRhIGZyYW1lcyBvZiBtb2RlbCBmaXRzIHdpdGggYWRqdXN0ZWQgaW5wdXRzIGFuZCBvcHRpbWFsIHBhcmFtZXRlcnMKIyAycHAKVHdvcHAuZml0cyA8LSBsYXBwbHkoc2VxX2Fsb25nKHBhcnMuZml0LjJwcCksIGZ1bmN0aW9uKGkpIHsKICBwYXIuZngocGFycy5maXQuMnBwW1tpXV0sIGluLmZpdC4ycHBbW2ldXSwgdmVyYm9zZSA9IEZBTFNFLCBtb2QgPSAiMnBwIikKfSkKbmFtZXMoVHdvcHAuZml0cykgPC0gbmFtZXMocGFycy5maXQuMnBwKQojIDJwcCBnYW0gPSBbLjUsIC45NV0KVHdvcHAucDMuNS45NS5maXRzIDwtIGxhcHBseShzZXFfYWxvbmcocGFycy5maXQuMnBwLnAzLjUuOTUpLCBmdW5jdGlvbihpKSB7CiAgcGFyLmZ4KHBhcnMuZml0LjJwcC5wMy41Ljk1W1tpXV0sIGluLmZpdC4ycHAucDMuNS45NVtbaV1dLCB2ZXJib3NlID0gRkFMU0UsIG1vZCA9ICIycHAiKQp9KQpuYW1lcyhUd29wcC5wMy41Ljk1LmZpdHMpIDwtIG5hbWVzKHBhcnMuZml0LjJwcC5wMy41Ljk1KQojIDJwcDIKVHdvcHAyLmZpdHMgPC0gbGFwcGx5KHNlcV9hbG9uZyhwYXJzLmZpdC4ycHAyKSwgZnVuY3Rpb24oaSkgewogIHBhci5meChwYXJzLmZpdC4ycHAyW1tpXV0sIGluLmZpdC4ycHAyW1tpXV0sIHZlcmJvc2UgPSBGQUxTRSwgbW9kID0gIjJwcCIpCn0pCm5hbWVzKFR3b3BwMi5maXRzKSA8LSBuYW1lcyhwYXJzLmZpdC4ycHAyKQojIDJwcwpUd29wcy5maXRzIDwtIGxhcHBseShzZXFfYWxvbmcocGFycy5maXQuMnBzKSwgZnVuY3Rpb24oaSkgewogIHBhci5meChwYXJzLmZpdC4ycHNbW2ldXSwgaW4uZml0LjJwc1tbaV1dLCB2ZXJib3NlID0gRkFMU0UsIG1vZCA9ICIycHMiKQp9KQpuYW1lcyhUd29wcy5maXRzKSA8LSBuYW1lcyhwYXJzLmZpdC4ycHMpCiMgMnBzMgpUd29wczIuZml0cyA8LSBsYXBwbHkoc2VxX2Fsb25nKHBhcnMuZml0LjJwczIpLCBmdW5jdGlvbihpKSB7CiAgcGFyLmZ4KHBhcnMuZml0LjJwczJbW2ldXSwgaW4uZml0LjJwczJbW2ldXSwgdmVyYm9zZSA9IEZBTFNFLCBtb2QgPSAiMnBzIiwgcGFzcyA9IFRSVUUpCn0pCm5hbWVzKFR3b3BzMi5maXRzKSA8LSBuYW1lcyhwYXJzLmZpdC4ycHMyKQoKIyMgc3RvY2sgYW5kIGJ1bGsgMTRDIGNvc3RzIG9ubHkKIyAycHAKVHdvcHA0LjEwLmZpdHMgPC0gbGFwcGx5KHNlcV9hbG9uZyhwYXJzLmZpdC4ycHA0LjEwKSwgZnVuY3Rpb24oaSkgewogIHBhci5meChwYXJzLmZpdC4ycHA0LjEwW1tpXV0sIGluLmVzdFtpeC4xMF1bW2ldXSwgdmVyYm9zZSA9IEZBTFNFLCBtb2QgPSAiMnBwIiwgcGFzcyA9IEZBTFNFKQp9KQpuYW1lcyhUd29wcDQuMTAuZml0cykgPC0gbmFtZXMocGFycy5maXQuMnBwNC4xMCkKVHdvcHA0LjMwLmZpdHMgPC0gbGFwcGx5KHNlcV9hbG9uZyhwYXJzLmZpdC4ycHA0LjMwKSwgZnVuY3Rpb24oaSkgewogIHBhci5meChwYXJzLmZpdC4ycHA0LjMwW1tpXV0sIGluLmVzdFtpeC4zMF1bW2ldXSwgdmVyYm9zZSA9IEZBTFNFLCBtb2QgPSAiMnBwIiwgcGFzcyA9IEZBTFNFKQp9KQpuYW1lcyhUd29wcDQuMzAuZml0cykgPC0gbmFtZXMocGFycy5maXQuMnBwNC4zMCkKIyAycHMKVHdvcHM0LjEwLmZpdHMgPC0gbGFwcGx5KHNlcV9hbG9uZyhwYXJzLmZpdC4ycHM0LjEwKSwgZnVuY3Rpb24oaSkgewogIHBhci5meChwYXJzLmZpdC4ycHM0LjEwW1tpXV0sIGluLmVzdFtpeC4xMF1bW2ldXSwgdmVyYm9zZSA9IEZBTFNFLCBtb2QgPSAiMnBzIiwgcGFzcyA9IEZBTFNFKQp9KQpuYW1lcyhUd29wczQuMTAuZml0cykgPC0gbmFtZXMocGFycy5maXQuMnBzNC4xMCkKVHdvcHM0LjMwLmZpdHMgPC0gbGFwcGx5KHNlcV9hbG9uZyhwYXJzLmZpdC4ycHM0LjMwKSwgZnVuY3Rpb24oaSkgewogIHBhci5meChwYXJzLmZpdC4ycHM0LjMwW1tpXV0sIGluLmVzdFtpeC4zMF1bW2ldXSwgdmVyYm9zZSA9IEZBTFNFLCBtb2QgPSAiMnBzIiwgcGFzcyA9IEZBTFNFKQp9KQpuYW1lcyhUd29wczQuMzAuZml0cykgPC0gbmFtZXMocGFycy5maXQuMnBzNC4zMCkKCiMjIHN0b2NrIGFuZCBidWxrICsgcmVzcCAxNEMgY29zdHMKIyAycHAKVHdvcHA0ci4xMC5maXRzIDwtIGxhcHBseShzZXFfYWxvbmcocGFycy5maXQuMnBwNHIuMTApLCBmdW5jdGlvbihpKSB7CiAgcGFyLmZ4KHBhcnMuZml0LjJwcDRyLjEwW1tpXV0sIGluLmVzdFtpeC4xMF1bW2ldXSwgdmVyYm9zZSA9IEZBTFNFLCBtb2QgPSAiMnBwIiwgcGFzcyA9IEZBTFNFKQp9KQpuYW1lcyhUd29wcDRyLjEwLmZpdHMpIDwtIG5hbWVzKHBhcnMuZml0LjJwcDRyLjEwKQpUd29wcDRyLjMwLmZpdHMgPC0gbGFwcGx5KHNlcV9hbG9uZyhwYXJzLmZpdC4ycHA0ci4zMCksIGZ1bmN0aW9uKGkpIHsKICBwYXIuZngocGFycy5maXQuMnBwNHIuMzBbW2ldXSwgaW4uZXN0W2l4LjMwXVtbaV1dLCB2ZXJib3NlID0gRkFMU0UsIG1vZCA9ICIycHAiLCBwYXNzID0gRkFMU0UpCn0pCm5hbWVzKFR3b3BwNHIuMzAuZml0cykgPC0gbmFtZXMocGFycy5maXQuMnBwNHIuMzApCiMgMnBzClR3b3BzNHIuMTAuZml0cyA8LSBsYXBwbHkoc2VxX2Fsb25nKHBhcnMuZml0LjJwczRyLjEwKSwgZnVuY3Rpb24oaSkgewogIHBhci5meChwYXJzLmZpdC4ycHM0ci4xMFtbaV1dLCBpbi5lc3RbaXguMTBdW1tpXV0sIHZlcmJvc2UgPSBGQUxTRSwgbW9kID0gIjJwcyIsIHBhc3MgPSBGQUxTRSkKfSkKbmFtZXMoVHdvcHM0ci4xMC5maXRzKSA8LSBuYW1lcyhwYXJzLmZpdC4ycHM0ci4xMCkKVHdvcHM0ci4zMC5maXRzIDwtIGxhcHBseShzZXFfYWxvbmcocGFycy5maXQuMnBzNHIuMzApLCBmdW5jdGlvbihpKSB7CiAgcGFyLmZ4KHBhcnMuZml0LjJwczRyLjMwW1tpXV0sIGluLmVzdFtpeC4zMF1bW2ldXSwgdmVyYm9zZSA9IEZBTFNFLCBtb2QgPSAiMnBzIiwgcGFzcyA9IEZBTFNFKQp9KQpuYW1lcyhUd29wczRyLjMwLmZpdHMpIDwtIG5hbWVzKHBhcnMuZml0LjJwczRyLjMwKQpgYGAKCmBgYHtyIHBsb3Qtc29jLXN0b2Nrc30KIyBQbG90IG9wdGltaXplZCBtb2RlbCBTT0Mgc3RvY2tzCm1vZC5zb2NzLmRmLmZ4IDwtIGZ1bmN0aW9uKG1vZCwgbW9kLnNvY3MubHMsIHBvb2xzKSB7CiAgbiA8LSB2YXBwbHkobW9kLnNvY3MubHMsIG5yb3csIG51bWVyaWMoMSkpCiAgcmV0dXJuKGRhdGEuZnJhbWUoU09DID0gZG8uY2FsbChyYmluZCwgbW9kLnNvY3MubHMpLAogICAgICAgICAgICAgICAgICAgIHBvb2wgPSByZXAocG9vbHMsIGxlbmd0aChtb2Quc29jcy5scykpLAogICAgICAgICAgICAgICAgICAgIFBNZWNvX2RlcHRoID0gcmVwKG5hbWVzKG1vZC5zb2NzLmxzKSwgbiksCiAgICAgICAgICAgICAgICAgICAgTW9kZWwgPSByZXAobW9kLCBzdW0obikpKSkgICAgICAgCn0KIyBydW4gZngKIyBtb2Quc29jcy4ycC5kZiA8LSByYmluZChtb2Quc29jcy5kZi5meCgiMnBwIiwgbW9kLnNvY3MuMnBwLmxzLCBjKCJmYXN0IiwgInNsb3ciKSkKIyAgICAgICAgICAgICAgICAgICAgICAgICAsbW9kLnNvY3MuZGYuZngoIjJwcyIsIG1vZC5zb2NzLjJwcy5scywgYygiZmFzdCIsICJzbG93IikpCiMgICAgICAgICAgICAgICAgICAgICAgICAgLG1vZC5zb2NzLmRmLmZ4KCIycHAgWy41LC45NV0iLCBtb2Quc29jcy4ycHAucDMuNS45NS5scywgYygiZmFzdCIsICJzbG93IikpCiMgICAgICAgICAgICAgICAgICAgICAgICAgLG1vZC5zb2NzLmRmLmZ4KCIycHMyIiwgbW9kLnNvY3MuMnBzMi5scywgYygiZmFzdCIsICJzbG93IikpCiMgICAgICAgICAgICAgICAgICAgICAgICAgLG1vZC5zb2NzLmRmLmZ4KCIycHAyIiwgbW9kLnNvY3MuMnBwMi5scywgYygiZmFzdCIsICJzbG93IikpCiMgICAgICAgICAgICAgICAgICAgICAgICAgKQptb2Quc29jcy4ycC5kZiA8LSByYmluZChtb2Quc29jcy5kZi5meCgiMnBwIiwgbW9kLnNvY3MuMnBwLmxzLCBjKCJmYXN0IiwgInNsb3ciKSkKICAgICAgICAgICAgICAgICAgICAgICAgLG1vZC5zb2NzLmRmLmZ4KCIycHMiLCBtb2Quc29jcy4ycHMubHMsIGMoImZhc3QiLCAic2xvdyIpKQogICAgICAgICAgICAgICAgICAgICAgICApCgoKIyBzdG9ja3MgYW5kIGJ1bGsgMTRDIG9ubHkKbW9kLnNvY3MuMnA0LjEwLmRmIDwtIHJiaW5kKG1vZC5zb2NzLmRmLmZ4KCIycHA0IDAtMTAiLCBtb2Quc29jcy4ycHA0LjEwLmxzLCBjKCJmYXN0IiwgInNsb3ciKSksIG1vZC5zb2NzLmRmLmZ4KCIycHM0IDAtMTAiLCBtb2Quc29jcy4ycHM0LjEwLmxzLCBjKCJmYXN0IiwgInNsb3ciKSkpCm1vZC5zb2NzLjJwNC4zMC5kZiA8LSByYmluZChtb2Quc29jcy5kZi5meCgiMnBwNCAyMC0zMCIsIG1vZC5zb2NzLjJwcDQuMzAubHMsIGMoImZhc3QiLCAic2xvdyIpKSAsbW9kLnNvY3MuZGYuZngoIjJwczQgMjAtMzAiLCBtb2Quc29jcy4ycHM0LjMwLmxzLCBjKCJmYXN0IiwgInNsb3ciKSkpCgojIHN0b2NrcyBhbmQgYnVsayArIHJlc3AgMTRDCm1vZC5zb2NzLjJwNHIuMTAuZGYgPC0gcmJpbmQobW9kLnNvY3MuZGYuZngoIjJwcDRyIDAtMTAiLCBtb2Quc29jcy4ycHA0ci4xMC5scywgYygiZmFzdCIsICJzbG93IikpLCBtb2Quc29jcy5kZi5meCgiMnBzNHIgMC0xMCIsIG1vZC5zb2NzLjJwczRyLjEwLmxzLCBjKCJmYXN0IiwgInNsb3ciKSkpCm1vZC5zb2NzLjJwNHIuMzAuZGYgPC0gcmJpbmQobW9kLnNvY3MuZGYuZngoIjJwcDRyIDIwLTMwIiwgbW9kLnNvY3MuMnBwNHIuMzAubHMsIGMoImZhc3QiLCAic2xvdyIpKSAsbW9kLnNvY3MuZGYuZngoIjJwczRyIDIwLTMwIiwgbW9kLnNvY3MuMnBzNHIuMzAubHMsIGMoImZhc3QiLCAic2xvdyIpKSkKCiMgY29tYmluZSBpbnB1dHMgdG8gY29tcGFyZQojIGluLmZpdHMuZGYgPC0gcGl2b3RfbG9uZ2VyKGRvLmNhbGwoYmluZF9yb3dzLCBsaXN0KGluLmZpdC4ycHAsCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaW4uZml0LjJwcC5wMy41Ljk1LAojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGluLmZpdC4ycHAyLAojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGluLmZpdC4ycHMsCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaW4uZml0LjJwczIpKSwKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICBldmVyeXRoaW5nKCksCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmFtZXNfdG8gPSAiUE1lY29fZGVwdGgiLAojICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlc190byA9ICJpbnB1dHMiKQojIGluLmZpdHMuZGYkbW9kIDwtIHJlcChjKCIycHAiLAojICAgICAgICAgICAgICAgICAgICAgICAgICIycHAuNS45NSIsCiMgICAgICAgICAgICAgICAgICAgICAgICAgIjJwcDIiLAojICAgICAgICAgICAgICAgICAgICAgICAgICIycHMiLAojICAgICAgICAgICAgICAgICAgICAgICAgICIycHMyIiksCiMgICAgICAgICAgICAgICAgICAgICAgIGVhY2ggPSA5KQppbi5maXRzLmRmIDwtIHBpdm90X2xvbmdlcihkby5jYWxsKGJpbmRfcm93cywgbGlzdChpbi5maXQuMnBwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbi5maXQuMnBzKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGV2ZXJ5dGhpbmcoKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgbmFtZXNfdG8gPSAiUE1lY29fZGVwdGgiLAogICAgICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZXNfdG8gPSAiaW5wdXRzIikKaW4uZml0cy5kZiRtb2QgPC0gcmVwKGMoIjJwcCIsCiAgICAgICAgICAgICAgICAgICAgICAgICIycHMiKSwKICAgICAgICAgICAgICAgICAgICAgIGVhY2ggPSA5KQogICAgICAgICAgICAgICAgICAgICAgICAKIyMgcGxvdCBzdG9ja3MKIyBzdG9jayBhbmQgYnVsayAxNEMgb25seQptb2Quc29jcy4ycDQuMTAuZGYgJT4lCiAgbXV0YXRlKFBNID0gc3Vic3RyKFBNZWNvX2RlcHRoLCAxLCAyKSwKICAgICAgICAgZWNvID0gZmFjdG9yKHN1YnN0cihQTWVjb19kZXB0aCwgMywgNCksIGxldmVscyA9IGMoInBwIiwgIndmIiwgInJmIikpKSAlPiUKICBnZ3Bsb3QoLiwgYWVzKHBvb2wsIFNPQywgZmlsbCA9IE1vZGVsKSkgKwogIGdlb21fY29sKHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2UoKSkgKwogIGZhY2V0X2dyaWQocm93cyA9IHZhcnMoZWNvKSwgY29scyA9IHZhcnMoUE0pKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUocGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSkKbW9kLnNvY3MuMnA0LjMwLmRmICU+JQogIG11dGF0ZShQTSA9IHN1YnN0cihQTWVjb19kZXB0aCwgMSwgMiksCiAgICAgICAgIGVjbyA9IGZhY3RvcihzdWJzdHIoUE1lY29fZGVwdGgsIDMsIDQpLCBsZXZlbHMgPSBjKCJwcCIsICJ3ZiIsICJyZiIpKSkgJT4lCiAgZ2dwbG90KC4sIGFlcyhwb29sLCBTT0MsIGZpbGwgPSBNb2RlbCkpICsKICBnZW9tX2NvbChwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKCkpICsKICBmYWNldF9ncmlkKHJvd3MgPSB2YXJzKGVjbyksIGNvbHMgPSB2YXJzKFBNKSkgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCkpCiMgc3RvY2sgYW5kIGJ1bGsgKyByZXNwIDE0Qwptb2Quc29jcy4ycDRyLjEwLmRmICU+JQogIG11dGF0ZShQTSA9IHN1YnN0cihQTWVjb19kZXB0aCwgMSwgMiksCiAgICAgICAgIGVjbyA9IGZhY3RvcihzdWJzdHIoUE1lY29fZGVwdGgsIDMsIDQpLCBsZXZlbHMgPSBjKCJwcCIsICJ3ZiIsICJyZiIpKSkgJT4lCiAgZ2dwbG90KC4sIGFlcyhwb29sLCBTT0MsIGZpbGwgPSBNb2RlbCkpICsKICBnZW9tX2NvbChwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKCkpICsKICBmYWNldF9ncmlkKHJvd3MgPSB2YXJzKGVjbyksIGNvbHMgPSB2YXJzKFBNKSkgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCkpCm1vZC5zb2NzLjJwNHIuMzAuZGYgJT4lCiAgbXV0YXRlKFBNID0gc3Vic3RyKFBNZWNvX2RlcHRoLCAxLCAyKSwKICAgICAgICAgZWNvID0gZmFjdG9yKHN1YnN0cihQTWVjb19kZXB0aCwgMywgNCksIGxldmVscyA9IGMoInBwIiwgIndmIiwgInJmIikpKSAlPiUKICBnZ3Bsb3QoLiwgYWVzKHBvb2wsIFNPQywgZmlsbCA9IE1vZGVsKSkgKwogIGdlb21fY29sKHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2UoKSkgKwogIGZhY2V0X2dyaWQocm93cyA9IHZhcnMoZWNvKSwgY29scyA9IHZhcnMoUE0pKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUocGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSkKCiMgaW5wdXRzCmluLmZpdHMuZGYgJT4lCiAgbXV0YXRlKFBNID0gc3Vic3RyKFBNZWNvX2RlcHRoLCAxLCAyKSwKICAgICAgICAgIyBNb2RlbCA9IGZhY3RvcihNb2RlbCwgbGV2ZWxzID0gYygiMnBwIFsuNSwuOTVdIiwgIjJwcCIsICIycHMiKSksCiAgICAgICAgIGVjbyA9IGZhY3RvcihzdWJzdHIoUE1lY29fZGVwdGgsIDMsIDQpLCBsZXZlbHMgPSBjKCJwcCIsICJ3ZiIsICJyZiIpKSkgJT4lCiAgZ2dwbG90KC4sIGFlcyhtb2QsIGlucHV0cywgZmlsbCA9IG1vZCkpICsKICBnZW9tX2NvbChwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKCkpICsKICBmYWNldF9ncmlkKHJvd3MgPSB2YXJzKGVjbyksIGNvbHMgPSB2YXJzKFBNKSkgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCkpCmBgYAoKYGBge3IgcGxvdC1vcHQtbW9kLTJwcH0KIyBwbG90IGZ4ClR3b3AuZml0LnBsb3QuZnggPC0gZnVuY3Rpb24oZml0MSwgZml0MS5uYW1lLCBmaXQyLCBmaXQyLm5hbWUsIGZpdDMgPSBOVUxMLCBmaXQzLm5hbWUgPSBOVUxMKSB7CiAgbGFwcGx5KHNlcV9hbG9uZyhmaXQxKSwgZnVuY3Rpb24oaSkgewogICAgUE1lY28gPC0gc3Vic3RyKG5hbWVzKGZpdDEpW2ldLCAxLCA0KQogICAgbHlyX2JvdCA8LSBzdWJzdHIobmFtZXMoZml0MSlbaV0sIAogICAgICAgICAgICAgICAgICAgICAgbmNoYXIobmFtZXMoZml0MSlbaV0pIC0gMSwgCiAgICAgICAgICAgICAgICAgICAgICBuY2hhcihuYW1lcyhmaXQxKVtpXSkpCiAgICBseXJfdG9wIDwtIGlmZWxzZShseXJfYm90ID09IDEwLCAwLCBpZmVsc2UobHlyX2JvdCA9PSAyMCwgMTAsIDIwKSkKICAgIFBNZWNvX2RlcHRoIDwtIG5hbWVzKGZpdDEpW2ldCiAgICBjb24uZGYgPC0gY29uLmRmLmZ4KFBNZWNvX2RlcHRoKQogICAgcGxvdC5kZiA8LSByYmluZChmaXQxW1tpXV0sCiAgICAgICAgICAgICAgICAgICAgIGZpdDJbW2ldXSwKICAgICAgICAgICAgICAgICAgICAgZml0M1tbaV1dKQogICAgcGxvdC5kZiRNb2RlbCA8LSBmYWN0b3IoYyhyZXAoZml0MS5uYW1lLCBucm93KGZpdDFbW2ldXSkpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXAoZml0Mi5uYW1lLCBucm93KGZpdDJbW2ldXSkpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXAoZml0My5uYW1lLCBucm93KGZpdDNbW2ldXSkpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoZml0MS5uYW1lLCBmaXQyLm5hbWUsIGZpdDMubmFtZSkpCiAgICByZXR1cm4ocGxvdC5kZiAlPiUKICAgICAgICAgICAgIGZpbHRlcihwb29sID09ICJidWxrIEMiIHwgcG9vbCA9PSAicmVzcGlyYXRpb24iIHwgcG9vbCA9PSAiYXRtIikgJT4lCiAgICAgICAgICAgICBnZ3Bsb3QoLiwgYWVzKHllYXJzLCBkMTRDLCBjb2xvciA9IHBvb2wpKSArCiAgICAgICAgICAgICBnZW9tX3BhdGgoYWVzKGxpbmV0eXBlID0gTW9kZWwpKSArCiAgICAgICAgICAgICBnZW9tX3BvaW50KGRhdGEgPSBjb24uZGYsIGFlcyhZZWFyLCBkMTRjLCBjb2xvciA9IHBvb2wpLCBzaXplID0gMykgKwogICAgICAgICAgICAgc2NhbGVfY29sb3JfbWFudWFsKAogICAgICAgICAgICAgICBuYW1lID0gIk1vZGVsIHBvb2wiLAogICAgICAgICAgICAgICB2YWx1ZXMgPSBjKCJhdG0iID0gOCwKICAgICAgICAgICAgICAgICAgICAgICAgICAiYnVsayBDIiA9ICJibGFjayIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgImZhc3QiID0gIiNEODFCNjAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICJzbG93IiA9ICIjMUU4OEU1IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAicmVzcGlyYXRpb24iID0gIiNGRkMxMDciKSkgKwogICAgICAgICAgICAgc2NhbGVfeF9jb250aW51b3VzKGxpbWl0cyA9IGMoMTk1MCwgMjAyMikpICsKICAgICAgICAgICAgIGdndGl0bGUocGFzdGUwKFBNZWNvX2RlcHRoLCAiIDJwIG1vZCBmaXRzIikpICsKICAgICAgICAgICAgIHhsYWIoIlllYXIiKSArCiAgICAgICAgICAgICB5bGFiKGV4cHJlc3Npb24oJycqRGVsdGEqJydeMTQqJ0MgKOKAsCknKSkgKwogICAgICAgICAgICAgdGhlbWVfYncoKSArCiAgICAgICAgICAgICB0aGVtZShwYW5lbC5ncmlkID0gZWxlbWVudF9ibGFuaygpKSkKICB9KQp9CiMgMnAgbW9kRml0IG9wdGltYWwgbW9kZWwgY29tcGFyaXNvbgpUd29wLmZpdHMucGxvdHMgPC0gVHdvcC5maXQucGxvdC5meChUd29wcC5maXRzLCAiMnBwIiwgVHdvcHMuZml0cywgIjJwcyIpClR3b3AuZml0cy5wbG90cwojIFR3b3AuZml0cy5wbG90czIgPC0gVHdvcC5maXQucGxvdC5meChUd29wcC5maXRzLCAiMnBwIiwgVHdvcHAucDMuNS45NS5maXRzLCAiMnBwIGdhbSA9IFsuNSwgLjk1XSIpCiMgVHdvcC5maXRzLnBsb3RzMgpUd29wLmZpdHMucGxvdHMzIDwtIFR3b3AuZml0LnBsb3QuZngoVHdvcHAucDMuNS45NS5maXRzLCAiMnBwIGdhbSA9IFsuNSwgLjk1XSIsIFR3b3BwMi5maXRzLCAiMnBwMiIpClR3b3AuZml0cy5wbG90czMKCiMjIGNvbXBhcmUgZml0cyB3LyBhbmQgdy9vIHJlc3AgY29uc3RyYWludCAoMnA0IG1vZHMpCiMgMnBwClR3b3BwNC5maXRzLnBsb3RzLjEwIDwtIFR3b3AuZml0LnBsb3QuZngoVHdvcHA0LjEwLmZpdHMsICIycHA0IDAtMTBjbSB3L28gcmVzcCIsIFR3b3BwNHIuMTAuZml0cywgIjJwcDRyIDAtMTBjbSB3LyByZXNwIikKVHdvcHA0LmZpdHMucGxvdHMuMzAgPC0gVHdvcC5maXQucGxvdC5meChUd29wcDQuMzAuZml0cywgIjJwcDQgMjAtMzBjbSB3L28gcmVzcCIsIFR3b3BwNHIuMTAuZml0cywgIjJwcDRyIDIwLTMwY20gdy8gcmVzcCIpCiMgMnBzClR3b3BzNC5maXRzLnBsb3RzLjEwIDwtIFR3b3AuZml0LnBsb3QuZngoVHdvcHM0LjEwLmZpdHMsICIycHM0IDAtMTBjbSB3L28gcmVzcCIsIFR3b3BzNHIuMTAuZml0cywgIjJwczRyIDAtMTBjbSB3LyByZXNwIikKVHdvcHM0LmZpdHMucGxvdHMuMzAgPC0gVHdvcC5maXQucGxvdC5meChUd29wczQuMzAuZml0cywgIjJwczQgMjAtMzBjbSB3L28gcmVzcCIsIFR3b3BzNHIuMTAuZml0cywgIjJwczRyIDIwLTMwY20gdy8gcmVzcCIpCiMgcGxvdApUd29wcDQuZml0cy5wbG90cy4xMApUd29wcDQuZml0cy5wbG90cy4zMApUd29wczQuZml0cy5wbG90cy4xMApUd29wczQuZml0cy5wbG90cy4zMApgYGAKCmBgYHtyIFNBQi1vYnN9CnAgPC0gc3JhLnRzLmFsbCAlPiUKICAgIGZpbHRlcihkMTRjID4gLTIwMCkgJT4lCiAgICBmaWx0ZXIoRUNPICE9ICJyZiIpICU+JQogICAgZmlsdGVyKGx5cl9ib3QgPT0gMjApICU+JQogICAgZmlsdGVyKHllYXIgIT0gMjAwOSkgJT4lCiAgICBnZ3Bsb3QoLiwgYWVzKHllYXIsIGQxNGMpKSArCiAgICBnZW9tX3BhdGgoZGF0YSA9IGF0bS4xNGMpICsKICAgIGdlb21fcG9pbnQoYWVzKGNvbG9yID0gcG0sIHNoYXBlID0gZWNvVHlwZSksIHNpemUgPSAzLjUpICsKICAgIGdlb21fcGF0aChhZXMoY29sb3IgPSBwbSwgbGluZXR5cGUgPSBUeXBlKSwgc2l6ZSA9IDEsIGFscGhhID0gMC4zKSArCiAgICBnZW9tX2Vycm9yYmFyKAogICAgICAgIGFlcyh5bWluID0gZDE0Y19sLCAKICAgICAgICAgICAgeW1heCA9IGQxNGNfdSwKICAgICAgICAgICAgY29sb3IgPSBwbSksIAogICAgICAgIHdpZHRoID0gLjUpICsKICAgIHNjYWxlX2NvbG9yX21hbnVhbChuYW1lID0gIlBhcmVudCBtYXRlcmlhbCIsCiAgICAgICAgICAgICAgICAgICAgICAgdmFsdWVzID0gYygiYW5kZXNpdGUiID0gImJsdWUiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJiYXNhbHQiID0gInJlZCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImdyYW5pdGUiID0gImRhcmtncmF5IikpICsKICAgIHNjYWxlX3NoYXBlX21hbnVhbChuYW1lID0gIkVjb3N5c3RlbSAodHlwZSkiLAogICAgICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9IGMoIndhcm0gKGluYykiID0gMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJjb29sIChpbmMpIiA9IDEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiY29sZCAoaW5jKSIgPSAyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIndhcm0gKGJ1bGspIiA9IDE1LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImNvb2wgKGJ1bGspIiA9IDE2LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImNvbGQgKGJ1bGspIiA9IDE3KSkgKwogICAgZmFjZXRfZ3JpZChyb3dzID0gdmFycyhlY28pLCBjb2xzID0gdmFycyhwbSkpICsKICAgIHlsYWIoZXhwcmVzc2lvbihEZWx0YSonJ14xNConQyAo4oCwKScpKSArCiAgICB4bGFiKCJZZWFyIikgKwogICAgZ2d0aXRsZSgiQnVsay9pbmMgMTAtMjAgY20iKSArCiAgICB0aGVtZV9idygpICsKICAgIHRoZW1lKHBhbmVsLmdyaWQgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gOCkpCmdnc2F2ZSgic3JhLnRzLnBwd2YyMC5ibGsuaW5jLnBkZiIsIHAsIGRwaSA9IDMwMCwgd2lkdGggPSA2Ljk3LCBoZWlnaHQgPSA1LCB1bml0cyA9ICJpbiIpCiMgaW5jL2J1bGsgcHJvZmlsZXMKcCA8LSBzcmEuMTkuMDEuMDkgJT4lCiAgZmlsdGVyKGx5cl9ib3QgPCAzMSkgJT4lCiAgc2VsZWN0KFllYXIsIFBNLCBFQ08sIFBNZWNvLCBseXJfYm90LCBkMTRjLCBkMTRjX3NkKSAlPiUKICBtdXRhdGUoVHlwZSA9ICJidWxrIiwKICAgICAgICAgZDE0Y191ID0gZDE0YyArIGQxNGNfc2QsCiAgICAgICAgIGQxNGNfbCA9IGQxNGMgLSBkMTRjX3NkLAogICAgICAgICB5ZWFyID0gYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoWWVhcikpKSAlPiUKICBzZWxlY3QoLWQxNGNfc2QpICU+JQogIGJpbmRfcm93cyguLAogICAgICAgICAgICBzcmEuMTkuMDEuaW5jICU+JQogICAgICAgICAgICAgIHNlbGVjdCh5ZWFyLCBQTSwgRUNPLCBQTWVjbywgbHlyX2JvdCwgZDE0YywgZDE0Y19taW4sIGQxNGNfbWF4KSAlPiUKICAgICAgICAgICAgICByZW5hbWUoZDE0Y19sID0gZDE0Y19taW4sCiAgICAgICAgICAgICAgICAgICAgIGQxNGNfdSA9IGQxNGNfbWF4KSAlPiUKICAgICAgICAgICAgICBtdXRhdGUoVHlwZSA9ICJpbmMiKQogICkgJT4lCiAgbXV0YXRlKGRlcHRoID0gZmFjdG9yKGx5cl9ib3QpLAogICAgICAgICBlY28gPSBmYWN0b3IoaWZlbHNlKEVDTyA9PSAicHAiLCAid2FybSIsCiAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoRUNPID09ICJ3ZiIsICJjb29sIiwgImNvbGQiKSksCiAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSBjKCJ3YXJtIiwgImNvb2wiLCAiY29sZCIpKSwKICAgICAgICAgcG0gPSBpZmVsc2UoUE0gPT0gIkFOIiwgImFuZGVzaXRlIiwKICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKFBNID09ICJCUyIsICJiYXNhbHQiLCAiZ3Jhbml0ZSIpKSwKICAgICAgICAgZWNvVHlwZSA9IHBhc3RlMChlY28sICIgKCIsIFR5cGUsICIpIikpCmdnc2F2ZSgic3JhLnRzLnBwd2YyMC5ibGsucGRmIiwgcCwgZHBpID0gMzAwLCB3aWR0aCA9IDYuOTcsIGhlaWdodCA9IDUsIHVuaXRzID0gImluIikKYGBgCgpgYGB7ciBTQUItbW9kZml0c30KIyMjIFJ1biBtb2RmaXQKIyMgMTRDIGJ1bGsgb25seQojIDAtMTAKbW9kLnNlbnMuZml0cy4ycHMuMTBiIDwtIG1vZC5maXRzLmZ4KG1vZCA9ICIycHMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFycyA9IHBhcnMuaS4ycHMsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3ViID0gaXguMTAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBJbiA9IGluLmVzdCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVwcGVyID0gYygxLCAuMDIsIC45OTkpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG93ZXIgPSBjKC4wMiwgLjAwMDEsIC4wMDEpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29zdCA9ICIxNEMgYnVsayBvbmx5IikKbmFtZXMobW9kLnNlbnMuZml0cy4ycHMuMTBiKSA8LSBuYW1lcyhwYXJzLmkuMnBzKVtpeC4xMF0Kc2F2ZShtb2Quc2Vucy5maXRzLjJwcy4xMGIsIGZpbGUgPSBwYXN0ZTAoIi4uL2RhdGEvZGVyaXZlZC9tb2RGaXRfcGFycy8iLCAibW9kLmZpdHMuMnBzLjEwYiIsICJfIiwgU3lzLkRhdGUoKSwgIi5SZGF0YSIpKQojICMgMjAtMzAKIyBtb2Quc2Vucy5maXRzLjJwcy4zMGIgPC0gbW9kLmZpdHMuZngobW9kID0gIjJwcyIsCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcnMgPSBwYXJzLmkuMnBzLCAKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3ViID0gaXguMzAsCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEluID0gaW4uZXN0LAojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1cHBlciA9IGMoMSwgLjAyLCAuMTUpLAojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb3dlciA9IGMoLjAwNSwgLjAwMDEsIC4wMDA0KSwKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29zdCA9ICIxNEMgYnVsayBvbmx5IikKIyBuYW1lcyhtb2Quc2Vucy5maXRzLjJwcy4zMGIpIDwtIG5hbWVzKHBhcnMuaS4ycHMpW2l4LjMwXQojIHNhdmUobW9kLnNlbnMuZml0cy4ycHMuMzBiLCBmaWxlID0gcGFzdGUwKCIuLi9kYXRhL2Rlcml2ZWQvbW9kRml0X3BhcnMvIiwgIm1vZC5maXRzLjJwcy4zMGIiLCAiXyIsIFN5cy5EYXRlKCksICIuUmRhdGEiKSkKIyBtb2QuZml0cy4ycHMuMzBiIDwtIGxhcHBseShtb2Quc2Vucy5maXRzLjJwcy4zMGIsIGZ1bmN0aW9uKHgpIHhbWzFdXSkKCiMjIDE0QyAoYnVsayArIHJlc3ApCiMgMC0xMAptb2Quc2Vucy5maXRzLjJwcy4xMGJyIDwtIG1vZC5maXRzLmZ4KG1vZCA9ICIycHMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFycyA9IHBhcnMuaS4ycHMsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3ViID0gaXguMTAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBJbiA9IGluLmVzdCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVwcGVyID0gYygxLCAuMDIsIC45OTkpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG93ZXIgPSBjKC4wMiwgLjAwMDEsIC4wMDEpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29zdCA9ICIxNEMiKQpuYW1lcyhtb2Quc2Vucy5maXRzLjJwcy4xMGJyKSA8LSBuYW1lcyhwYXJzLmkuMnBzKVtpeC4xMF0Kc2F2ZShtb2Quc2Vucy5maXRzLjJwcy4xMGJyLCBmaWxlID0gcGFzdGUwKCIuLi9kYXRhL2Rlcml2ZWQvbW9kRml0X3BhcnMvIiwgIm1vZC5maXRzLjJwcy4xMGJyIiwgIl8iLCBTeXMuRGF0ZSgpLCAiLlJkYXRhIikpCiMgMTAtMjAsIGxhZyA9IDUKbW9kLnNlbnMuZml0cy4ycHMuMjBici5sIDwtIG1vZC5maXRzLmZ4KG1vZCA9ICIycHMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJzID0gcGFycy5pLjJwcywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3ViID0gaXguMjAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEluID0gaW4uZXN0LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhZyA9IDUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVwcGVyID0gYygxLCAuMDIsIC45OSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvd2VyID0gYyguMDIsIC4wMDAxLCAuMDEpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb3N0ID0gIjE0QyIpCm5hbWVzKG1vZC5zZW5zLmZpdHMuMnBzLjIwYnIubCkgPC0gbmFtZXMocGFycy5pLjJwcylbaXguMjBdCnNhdmUobW9kLnNlbnMuZml0cy4ycHMuMjBici5sLCBmaWxlID0gcGFzdGUwKCIuLi9kYXRhL2Rlcml2ZWQvbW9kRml0X3BhcnMvIiwgIm1vZC5maXRzLjJwcy4yMGJyLmwiLCAiXyIsIFN5cy5EYXRlKCksICIuUmRhdGEiKSkKIyAjIDIwLTMwCiMgbW9kLnNlbnMuZml0cy4ycHMuMzBiciA8LSBtb2QuZml0cy5meChtb2QgPSAiMnBzIiwKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFycyA9IHBhcnMuaS4ycHMsIAojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdWIgPSBpeC4zMCwKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgSW4gPSBpbi5lc3QsCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVwcGVyID0gYygxLCAuMDIsIC4xNSksCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvd2VyID0gYyguMDA1LCAuMDAwMSwgLjAwMDQpLAojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb3N0ID0gIjE0QyIpCiMgbmFtZXMobW9kLnNlbnMuZml0cy4ycHMuMzBicikgPC0gbmFtZXMocGFycy5pLjJwcylbaXguMzBdCiMgc2F2ZShtb2Quc2Vucy5maXRzLjJwcy4zMGJyLCBmaWxlID0gcGFzdGUwKCIuLi9kYXRhL2Rlcml2ZWQvbW9kRml0X3BhcnMvIiwgIm1vZC5maXRzLjJwcy4zMGJyIiwgIl8iLCBTeXMuRGF0ZSgpLCAiLlJkYXRhIikpCiMgbW9kLmZpdHMuMnBzLjMwYnIgPC0gbGFwcGx5KG1vZC5zZW5zLmZpdHMuMnBzLjMwYnIsIGZ1bmN0aW9uKHgpIHhbWzFdXSkKCiMjIDE0QyBidWxrICsgc3RvY2tzCiMgMC0xMAptb2Quc2Vucy5maXRzLjJwcy4xMGJzIDwtIG1vZC5maXRzLmZ4KG1vZCA9ICIycHMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcnMgPSBwYXJzLmkuMnBzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1YiA9IGl4LjEwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEluID0gaW4uZXN0LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVwcGVyID0gYygxLCAuMDIsIC45OTkpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvd2VyID0gYyguMDIsIC4wMDAxLCAuMDAxKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb3N0ID0gIjE0QyBidWxrICsgY1N0b2NrIikKbmFtZXMobW9kLnNlbnMuZml0cy4ycHMuMTBicykgPC0gbmFtZXMocGFycy5pLjJwcylbaXguMTBdCnNhdmUobW9kLnNlbnMuZml0cy4ycHMuMTBicywgZmlsZSA9IHBhc3RlMCgiLi4vZGF0YS9kZXJpdmVkL21vZEZpdF9wYXJzLyIsICJtb2QuZml0cy4ycHMuMTBicyIsICJfIiwgU3lzLkRhdGUoKSwgIi5SZGF0YSIpKQptb2QuZml0cy4ycHMuMTBicyA8LSBsYXBwbHkobW9kLnNlbnMuZml0cy4ycHMuMTBicywgZnVuY3Rpb24oeCkgeFtbMV1dKQojICMgMjAtMzAKIyBtb2Quc2Vucy5maXRzLjJwcy4zMGIgPC0gbW9kLmZpdHMuZngobW9kID0gIjJwcyIsCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcnMgPSBwYXJzLmkuMnBzLCAKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3ViID0gaXguMzAsCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEluID0gaW4uZXN0LAojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1cHBlciA9IGMoMSwgLjAyLCAuMTUpLAojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb3dlciA9IGMoLjAwNSwgLjAwMDEsIC4wMDA0KSwKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29zdCA9ICIxNEMgYnVsayBvbmx5IikKIyBuYW1lcyhtb2Quc2Vucy5maXRzLjJwcy4zMGIpIDwtIG5hbWVzKHBhcnMuaS4ycHMpW2l4LjMwXQojIHNhdmUobW9kLnNlbnMuZml0cy4ycHMuMzBiLCBmaWxlID0gcGFzdGUwKCIuLi9kYXRhL2Rlcml2ZWQvbW9kRml0X3BhcnMvIiwgIm1vZC5maXRzLjJwcy4zMGIiLCAiXyIsIFN5cy5EYXRlKCksICIuUmRhdGEiKSkKIyBtb2QuZml0cy4ycHMuMzBiIDwtIGxhcHBseShtb2Quc2Vucy5maXRzLjJwcy4zMGIsIGZ1bmN0aW9uKHgpIHhbWzFdXSkKCiMjIDE0QyArIGNTdG9jayAoMTRDIHJlc3AsIDE0QyBidWxrLCBzdG9ja3MpCiMgMC0xMAptb2Quc2Vucy5maXRzLjJwcy4xMHJicyA8LSBtb2QuZml0cy5meChtb2QgPSAiMnBzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFycyA9IHBhcnMuaS4ycHMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1YiA9IGl4LjEwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBJbiA9IGluLmVzdCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdXBwZXIgPSBjKDEsIC4wMiwgLjk5OSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvd2VyID0gYyguMDIsIC4wMDAxLCAuMDAxKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29zdCA9ICIxNEMgKyBjU3RvY2siKQpuYW1lcyhtb2Quc2Vucy5maXRzLjJwcy4xMHJicykgPC0gbmFtZXMocGFycy5pLjJwcylbaXguMTBdCnNhdmUobW9kLnNlbnMuZml0cy4ycHMuMTByYnMsIGZpbGUgPSBwYXN0ZTAoIi4uL2RhdGEvZGVyaXZlZC9tb2RGaXRfcGFycy8iLCAibW9kLmZpdHMuMnBzLjEwcmJzIiwgIl8iLCBTeXMuRGF0ZSgpLCAiLlJkYXRhIikpCm1vZC5maXRzLjJwcy4xMHJicyA8LSBsYXBwbHkobW9kLnNlbnMuZml0cy4ycHMuMTByYnMsIGZ1bmN0aW9uKHgpIHhbWzFdXSkKIyAxMC0yMAojIHcvbyBsYWcKbW9kLnNlbnMuZml0cy4ycHMuMjByYnMgPC0gbW9kLmZpdHMuZngobW9kID0gIjJwcyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcnMgPSBwYXJzLmkuMnBzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdWIgPSBpeC4yMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgSW4gPSBpbi5lc3QsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVwcGVyID0gYygxLCAuMDIsIC45OSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvd2VyID0gYyguMDIsIC4wMDAxLCAuMDEpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb3N0ID0gIjE0QyArIGNTdG9jayIpCm5hbWVzKG1vZC5zZW5zLmZpdHMuMnBzLjIwcmJzKSA8LSBuYW1lcyhwYXJzLmkuMnBzKVtpeC4yMF0Kc2F2ZShtb2Quc2Vucy5maXRzLjJwcy4yMHJicywgZmlsZSA9IHBhc3RlMCgiLi4vZGF0YS9kZXJpdmVkL21vZEZpdF9wYXJzLyIsICJtb2QuZml0cy4ycHMuMjByYnMiLCAiXyIsIFN5cy5EYXRlKCksICIuUmRhdGEiKSkKIyB3LyBsYWcgPSAxMgptb2Quc2Vucy5maXRzLjJwcy4yMHJicy5sIDwtIG1vZC5maXRzLmZ4KG1vZCA9ICIycHMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJzID0gcGFycy5pLjJwcywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3ViID0gaXguMjAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEluID0gaW4uZXN0LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWcgPSAxMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdXBwZXIgPSBjKDEsIC4wMiwgLjk5KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG93ZXIgPSBjKC4wMiwgLjAwMDEsIC4wMSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvc3QgPSAiMTRDICsgY1N0b2NrIikKbmFtZXMobW9kLnNlbnMuZml0cy4ycHMuMjByYnMubCkgPC0gbmFtZXMocGFycy5pLjJwcylbaXguMjBdCnNhdmUobW9kLnNlbnMuZml0cy4ycHMuMjByYnMubCwgZmlsZSA9IHBhc3RlMCgiLi4vZGF0YS9kZXJpdmVkL21vZEZpdF9wYXJzLyIsICJtb2QuZml0cy4ycHMuMjByYnMubCIsICJfIiwgU3lzLkRhdGUoKSwgIi5SZGF0YSIpKQojICMgMjAtMzAKIyBtb2Quc2Vucy5maXRzLjJwcy4zMGIgPC0gbW9kLmZpdHMuZngobW9kID0gIjJwcyIsCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcnMgPSBwYXJzLmkuMnBzLCAKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3ViID0gaXguMzAsCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEluID0gaW4uZXN0LAojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1cHBlciA9IGMoMSwgLjAyLCAuMTUpLAojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb3dlciA9IGMoLjAwNSwgLjAwMDEsIC4wMDA0KSwKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29zdCA9ICIxNEMgYnVsayBvbmx5IikKIyBuYW1lcyhtb2Quc2Vucy5maXRzLjJwcy4zMGIpIDwtIG5hbWVzKHBhcnMuaS4ycHMpW2l4LjMwXQojIHNhdmUobW9kLnNlbnMuZml0cy4ycHMuMzBiLCBmaWxlID0gcGFzdGUwKCIuLi9kYXRhL2Rlcml2ZWQvbW9kRml0X3BhcnMvIiwgIm1vZC5maXRzLjJwcy4zMGIiLCAiXyIsIFN5cy5EYXRlKCksICIuUmRhdGEiKSkKIyBtb2QuZml0cy4ycHMuMzBiIDwtIGxhcHBseShtb2Quc2Vucy5maXRzLjJwcy4zMGIsIGZ1bmN0aW9uKHgpIHhbWzFdXSkKYGBgCgpgYGB7ciBTQUItbW9kLWZpdHN9CiMgU0FCIGZpdHMKbG9hZCgiLi4vZGF0YS9kZXJpdmVkL21vZEZpdF9wYXJzL21vZC5maXRzLjJwcy4xMGJfMjAyMS0wNC0wNy5SZGF0YSIpCmxvYWQoIi4uL2RhdGEvZGVyaXZlZC9tb2RGaXRfcGFycy9tb2QuZml0cy4ycHMuMTBicl8yMDIxLTA0LTA3LlJkYXRhIikKbG9hZCgiLi4vZGF0YS9kZXJpdmVkL21vZEZpdF9wYXJzL21vZC5maXRzLjJwcy4xMGJzXzIwMjEtMDQtMDcuUmRhdGEiKQpsb2FkKCIuLi9kYXRhL2Rlcml2ZWQvbW9kRml0X3BhcnMvbW9kLmZpdHMuMnBzLjEwcmJzXzIwMjEtMDQtMDcuUmRhdGEiKQpsb2FkKCIuLi9kYXRhL2Rlcml2ZWQvbW9kRml0X3BhcnMvbW9kLmZpdHMuMnBzLjIwcmJzXzIwMjEtMDQtMTIuUmRhdGEiKQpsb2FkKCIuLi9kYXRhL2Rlcml2ZWQvbW9kRml0X3BhcnMvbW9kLmZpdHMuMnBzLjIwcmJzLmxfMjAyMS0wNC0xMy5SZGF0YSIpCmxvYWQoIi4uL2RhdGEvZGVyaXZlZC9tb2RGaXRfcGFycy9tb2QuZml0cy4ycHMuMjBici5sXzIwMjEtMDQtMTMuUmRhdGEiKQpsb2FkKCIuLi9kYXRhL2Rlcml2ZWQvbW9kRml0X3BhcnMvcGFycy5pLjJwc18yMDIxLTA0LTA2LlJkYXRhIikKCiMgZXh0cmFjdCBtb2QgZml0cwptb2QuZml0cy4ycHMuMTBiIDwtIGxhcHBseShtb2Quc2Vucy5maXRzLjJwcy4xMGIsIGZ1bmN0aW9uKHgpIHhbWzFdXSkKbW9kLmZpdHMuMnBzLjEwYnMgPC0gbGFwcGx5KG1vZC5zZW5zLmZpdHMuMnBzLjEwYnMsIGZ1bmN0aW9uKHgpIHhbWzFdXSkKbW9kLmZpdHMuMnBzLjEwYnIgPC0gbGFwcGx5KG1vZC5zZW5zLmZpdHMuMnBzLjEwYnIsIGZ1bmN0aW9uKHgpIHhbWzFdXSkKbW9kLmZpdHMuMnBzLjEwcmJzIDwtIGxhcHBseShtb2Quc2Vucy5maXRzLjJwcy4xMHJicywgZnVuY3Rpb24oeCkgeFtbMV1dKQptb2QuZml0cy4ycHMuMjByYnMgPC0gbGFwcGx5KG1vZC5zZW5zLmZpdHMuMnBzLjIwcmJzLCBmdW5jdGlvbih4KSB4W1sxXV0pCm1vZC5maXRzLjJwcy4yMHJicy5sIDwtIGxhcHBseShtb2Quc2Vucy5maXRzLjJwcy4yMHJicy5sLCBmdW5jdGlvbih4KSB4W1sxXV0pCm1vZC5maXRzLjJwcy4yMGJyLmwgPC0gbGFwcGx5KG1vZC5zZW5zLmZpdHMuMnBzLjIwYnIubCwgZnVuY3Rpb24oeCkgeFtbMV1dKSAKICAKIyBTZW5zaXRpdml0eS9JZGVudGlmaWFiaWxpdHkKIyMjIyMKIyBleHRyYWN0IGF0IHNlbnNGdW4gb3V0cHV0CnNlbnMuMnBzLjEwYiA8LSBsYXBwbHkobW9kLnNlbnMuZml0cy4ycHMuMTBiLCBmdW5jdGlvbih4KSB4W1syXV0pCnNlbnMuMnBzLjEwYnIgPC0gbGFwcGx5KG1vZC5zZW5zLmZpdHMuMnBzLjEwYnIsIGZ1bmN0aW9uKHgpIHhbWzJdXSkKc2Vucy4ycHMuMTBicyA8LSBsYXBwbHkobW9kLnNlbnMuZml0cy4ycHMuMTBicywgZnVuY3Rpb24oeCkgeFtbMl1dKQpzZW5zLjJwcy4xMHJicyA8LSBsYXBwbHkobW9kLnNlbnMuZml0cy4ycHMuMTByYnMsIGZ1bmN0aW9uKHgpIHhbWzJdXSkKc2Vucy4ycHMuMjByYnMgPC0gbGFwcGx5KG1vZC5zZW5zLmZpdHMuMnBzLjIwcmJzLCBmdW5jdGlvbih4KSB4W1syXV0pCnNlbnMuMnBzLjIwcmJzLmwgPC0gbGFwcGx5KG1vZC5zZW5zLmZpdHMuMnBzLjIwcmJzLmwsIGZ1bmN0aW9uKHgpIHhbWzJdXSkKc2Vucy4ycHMuMjBici5sIDwtIGxhcHBseShtb2Quc2Vucy5maXRzLjJwcy4yMGJyLmwsIGZ1bmN0aW9uKHgpIHhbWzJdXSkKCiMgcGxvdCBzZW5zaXRpdml0eQpsYXBwbHkoc2Vucy4ycHMuMTBiLCBmdW5jdGlvbih4KSBwbG90KHgsIHdoaWNoID0gYygiYnVsa0MiLCAicmVzcCIpKSkKbGFwcGx5KHNlbnMuMnBzLjEwYnIsIGZ1bmN0aW9uKHgpIHBsb3QoeCwgd2hpY2ggPSBjKCJidWxrQyIsICJyZXNwIikpKQpsYXBwbHkoc2Vucy4ycHMuMTBicywgZnVuY3Rpb24oeCkgcGxvdCh4LCB3aGljaCA9IGMoImJ1bGtDIiwgInJlc3AiKSkpCmxhcHBseShzZW5zLjJwcy4xMHJicywgZnVuY3Rpb24oeCkgcGxvdCh4LCB3aGljaCA9IGMoImJ1bGtDIiwgInJlc3AiKSkpCgojIGxvb2sgYXQgaWRlbnRpZmlhYmlsaXR5CmlkZW4uMnBzLjEwYiA8LSBpbmRlbi5kZi5meChzZW5zLjJwcy4xMGIsIG1vZCA9ICIycHMiKQppZGVuLjJwcy4xMGJyIDwtIGluZGVuLmRmLmZ4KHNlbnMuMnBzLjEwYnIsIG1vZCA9ICIycHMiKQppZGVuLjJwcy4xMGJzIDwtIGluZGVuLmRmLmZ4KHNlbnMuMnBzLjEwYnMsIG1vZCA9ICIycHMiKQppZGVuLjJwcy4xMHJicyA8LSBpbmRlbi5kZi5meChzZW5zLjJwcy4xMHJicywgbW9kID0gIjJwcyIpCmlkZW4uMnBzLjIwcmJzIDwtIGluZGVuLmRmLmZ4KHNlbnMuMnBzLjIwcmJzLCBtb2QgPSAiMnBzIikKaWRlbi4ycHMuMjByYnMubCA8LSBpbmRlbi5kZi5meChzZW5zLjJwcy4yMHJicy5sLCBtb2QgPSAiMnBzIikKaWRlbi4ycHMuMjBici5sIDwtIGluZGVuLmRmLmZ4KHNlbnMuMnBzLjIwYnIubCwgbW9kID0gIjJwcyIpCgojIHBsb3QKbGFwcGx5KHNlcV9hbG9uZyhpZGVuLjJwcy4xMGJzKSwgZnVuY3Rpb24oaSkgewogIGNvbGwucGxvdC5meChpZGVuLjJwcy4xMGJzW1tpXV0sIG1vZCA9ICIycHMiLCAKICAgICAgICAgICAgICAgbmFtZXMoaWRlbi4ycHMuMTBicylbaV0sIAogICAgICAgICAgICAgICBtYXgoaWRlbi4ycHMuMTBic1tbaV1dWyJjb2xsaW5lYXJpdHkiXSkpCn0pCmxhcHBseShzZXFfYWxvbmcoaWRlbi4ycHMuMTBiciksIGZ1bmN0aW9uKGkpIHsKICBjb2xsLnBsb3QuZngoaWRlbi4ycHMuMTBicltbaV1dLCBtb2QgPSAiMnBzIiwgCiAgICAgICAgICAgICAgIG5hbWVzKGlkZW4uMnBzLjEwYnIpW2ldLCAKICAgICAgICAgICAgICAgbWF4KGlkZW4uMnBzLjEwYnJbW2ldXVsiY29sbGluZWFyaXR5Il0pKQp9KQpsYXBwbHkoc2VxX2Fsb25nKGlkZW4uMnBzLjEwcmJzKSwgZnVuY3Rpb24oaSkgewogIGNvbGwucGxvdC5meChpZGVuLjJwcy4xMHJic1tbaV1dLCBtb2QgPSAiMnBzIiwgCiAgICAgICAgICAgICAgIG5hbWVzKGlkZW4uMnBzLjEwcmJzKVtpXSwgCiAgICAgICAgICAgICAgIG1heChpZGVuLjJwcy4xMHJic1tbaV1dWyJjb2xsaW5lYXJpdHkiXSkpCn0pCmxhcHBseShzZXFfYWxvbmcoaWRlbi4ycHMuMjByYnMpLCBmdW5jdGlvbihpKSB7CiAgY29sbC5wbG90LmZ4KGlkZW4uMnBzLjIwcmJzW1tpXV0sIG1vZCA9ICIycHMiLCAKICAgICAgICAgICAgICAgbmFtZXMoaWRlbi4ycHMuMjByYnMpW2ldLCAKICAgICAgICAgICAgICAgbWF4KGlkZW4uMnBzLjIwcmJzW1tpXV1bImNvbGxpbmVhcml0eSJdKSkKfSkKbGFwcGx5KHNlcV9hbG9uZyhpZGVuLjJwcy4yMHJicy5sKSwgZnVuY3Rpb24oaSkgewogIGNvbGwucGxvdC5meChpZGVuLjJwcy4yMHJicy5sW1tpXV0sIG1vZCA9ICIycHMiLCAKICAgICAgICAgICAgICAgbmFtZXMoaWRlbi4ycHMuMjByYnMubClbaV0sIAogICAgICAgICAgICAgICBtYXgoaWRlbi4ycHMuMjByYnMubFtbaV1dWyJjb2xsaW5lYXJpdHkiXSkpCn0pCmxhcHBseShzZXFfYWxvbmcoaWRlbi4ycHMuMjBici5sKSwgZnVuY3Rpb24oaSkgewogIGNvbGwucGxvdC5meChpZGVuLjJwcy4yMGJyLmxbW2ldXSwgbW9kID0gIjJwcyIsIAogICAgICAgICAgICAgICBuYW1lcyhpZGVuLjJwcy4yMGJyLmwpW2ldLCAKICAgICAgICAgICAgICAgbWF4KGlkZW4uMnBzLjIwYnIubFtbaV1dWyJjb2xsaW5lYXJpdHkiXSkpCn0pCiMjIyMjCgojIEV4dHJhY3Qgb3B0aW1pemVkIHBhcnMgZnJvbSBtb2RmaXQgb3V0cHV0CiMjIyMjCiMjIGJ1bGsgMTRjIG9ubHkKIyAwLTEwCnBhcnMuZml0LjJwcy4xMGIgPC0gbGFwcGx5KG1vZC5maXRzLjJwcy4xMGIsICJbWyIsIDEpCm5hbWVzKHBhcnMuZml0LjJwcy4xMGIpIDwtIG5hbWVzKHBhcnMuaS4ycHMpW2l4LjEwXQojICMgMjAtMzAKIyBwYXJzLmZpdC4ycHMuMzBiIDwtIGxhcHBseShtb2QuZml0cy4ycHMuMzBiLCAiW1siLCAxKQojIG5hbWVzKHBhcnMuZml0LjJwcy4zMGIpIDwtIG5hbWVzKHBhcnMuaS4ycHMpW2l4LjMwXQoKIyMgcmVzcCArIGJ1bGsgMTRjCiMgMC0xMApwYXJzLmZpdC4ycHMuMTBiciA8LSBsYXBwbHkobW9kLmZpdHMuMnBzLjEwYnIsICJbWyIsIDEpCm5hbWVzKHBhcnMuZml0LjJwcy4xMGJyKSA8LSBuYW1lcyhwYXJzLmkuMnBzKVtpeC4xMF0KIyAxMC0yMCB3LyBsYWcgPSA1eQpwYXJzLmZpdC4ycHMuMjBici5sIDwtIGxhcHBseShtb2QuZml0cy4ycHMuMjBici5sLCAiW1siLCAxKQpuYW1lcyhwYXJzLmZpdC4ycHMuMjBici5sKSA8LSBuYW1lcyhwYXJzLmkuMnBzKVtpeC4yMF0KIyAjIDIwLTMwCiMgcGFycy5maXQuMnBzLjMwYnIgPC0gbGFwcGx5KG1vZC5maXRzLjJwcy4zMGJyLCAiW1siLCAxKQojIG5hbWVzKHBhcnMuZml0LjJwcy4zMGJyKSA8LSBuYW1lcyhwYXJzLmkuMnBzKVtpeC4zMF0KCiMjIGJ1bGsgMTRjICsgc3RvY2tzCiMgMC0xMApwYXJzLmZpdC4ycHMuMTBicyA8LSBsYXBwbHkobW9kLmZpdHMuMnBzLjEwYnMsICJbWyIsIDEpCm5hbWVzKHBhcnMuZml0LjJwcy4xMGJzKSA8LSBuYW1lcyhwYXJzLmkuMnBzKVtpeC4xMF0KIyAjIDIwLTMwCiMgcGFycy5maXQuMnBzLjMwYnIgPC0gbGFwcGx5KG1vZC5maXRzLjJwcy4zMGJyLCAiW1siLCAxKQojIG5hbWVzKHBhcnMuZml0LjJwcy4zMGJyKSA8LSBuYW1lcyhwYXJzLmkuMnBzKVtpeC4zMF0KCiMjIHJlc3AsIGJ1bGsgMTRjLCBzdG9ja3MKIyAwLTEwCnBhcnMuZml0LjJwcy4xMHJicyA8LSBsYXBwbHkobW9kLmZpdHMuMnBzLjEwcmJzLCAiW1siLCAxKQpuYW1lcyhwYXJzLmZpdC4ycHMuMTByYnMpIDwtIG5hbWVzKHBhcnMuaS4ycHMpW2l4LjEwXQojIDEwLTIwCnBhcnMuZml0LjJwcy4yMHJicyA8LSBsYXBwbHkobW9kLmZpdHMuMnBzLjIwcmJzLCAiW1siLCAxKQpuYW1lcyhwYXJzLmZpdC4ycHMuMjByYnMpIDwtIG5hbWVzKHBhcnMuaS4ycHMpW2l4LjIwXQojIDEwLTIwIHcvIGxhZyA9IDEyeQpwYXJzLmZpdC4ycHMuMjByYnMubCA8LSBsYXBwbHkobW9kLmZpdHMuMnBzLjIwcmJzLmwsICJbWyIsIDEpCm5hbWVzKHBhcnMuZml0LjJwcy4yMHJicy5sKSA8LSBuYW1lcyhwYXJzLmkuMnBzKVtpeC4yMF0KIyAjIDIwLTMwCiMgcGFycy5maXQuMnBzLjMwYnIgPC0gbGFwcGx5KG1vZC5maXRzLjJwcy4zMGJyLCAiW1siLCAxKQojIG5hbWVzKHBhcnMuZml0LjJwcy4zMGJyKSA8LSBuYW1lcyhwYXJzLmkuMnBzKVtpeC4zMF0KIyMjIyMKCiMgU09DIHN0b2NrcwojIyMjIwojIHcvbyBzdG9jayBjb25zdHJhaW50Cm1vZC5zb2NzLjJwcy4xMGIubHMgPC0gbGFwcGx5KHNlcV9hbG9uZyhwYXJzLmZpdC4ycHMuMTBiKSwgZnVuY3Rpb24oaSkgewogIHNvYy5meCgiMnBzIiwgcGFycy5maXQuMnBzLjEwYltbaV1dLCBpbi5lc3RbW2ldXSkKfSkKbmFtZXMobW9kLnNvY3MuMnBzLjEwYi5scykgPC0gbmFtZXMocGFycy5maXQuMnBzLjEwYikKbW9kLnNvY3MuMnBzLjEwYnIubHMgPC0gbGFwcGx5KHNlcV9hbG9uZyhwYXJzLmZpdC4ycHMuMTBiciksIGZ1bmN0aW9uKGkpIHsKICBzb2MuZngoIjJwcyIsIHBhcnMuZml0LjJwcy4xMGJyW1tpXV0sIGluLmVzdFtbaV1dKQp9KQpuYW1lcyhtb2Quc29jcy4ycHMuMTBici5scykgPC0gbmFtZXMocGFycy5maXQuMnBzLjEwYnIpCnNvY3MuMnBzLjEwYnIubHMgPC0gbWFwcGx5KGNiaW5kLAogICAgICAgICAgICAgICAgICAgICAgICAgICBjc29jLjE5LjBfMzBbaXguMTBdLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFwcGx5KG1vZC5zb2NzLjJwcy4xMGJyLmxzLCBjb2xTdW1zKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIFNJTVBMSUZZID0gRkFMU0UpCiMgdy8gc3RvY2sgY29uc3RyYWludAptb2Quc29jcy4ycHMuMTBicy5scyA8LSBsYXBwbHkoc2VxX2Fsb25nKHBhcnMuZml0LjJwcy4xMGJzKSwgZnVuY3Rpb24oaSkgewogIHNvYy5meCgiMnBzIiwgcGFycy5maXQuMnBzLjEwYnNbW2ldXSwgaW4uZXN0W1tpXV0pCn0pCm5hbWVzKG1vZC5zb2NzLjJwcy4xMGJzLmxzKSA8LSBuYW1lcyhwYXJzLmZpdC4ycHMuMTBicykKbW9kLnNvY3MuMnBzLjEwcmJzLmxzIDwtIGxhcHBseShzZXFfYWxvbmcocGFycy5maXQuMnBzLjEwcmJzKSwgZnVuY3Rpb24oaSkgewogIHNvYy5meCgiMnBzIiwgcGFycy5maXQuMnBzLjEwcmJzW1tpXV0sIGluLmVzdFtbaV1dKQp9KQpuYW1lcyhtb2Quc29jcy4ycHMuMTByYnMubHMpIDwtIG5hbWVzKHBhcnMuZml0LjJwcy4xMHJicykKbW9kLnNvY3MuMnBzLjIwcmJzLmxzIDwtIGxhcHBseShzZXFfYWxvbmcocGFycy5maXQuMnBzLjIwcmJzKSwgZnVuY3Rpb24oaSkgewogIHNvYy5meCgiMnBzIiwgcGFycy5maXQuMnBzLjIwcmJzW1tpXV0sIGluLmVzdFtpeC4yMF1bW2ldXSkKfSkKbmFtZXMobW9kLnNvY3MuMnBzLjIwcmJzLmxzKSA8LSBuYW1lcyhwYXJzLmZpdC4ycHMuMjByYnMpCnNvY3MuMnBzLjEwcmJzLmxzIDwtIG1hcHBseShjYmluZCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgY3NvYy4xOS4wXzMwW2l4LjEwXSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhcHBseShtb2Quc29jcy4ycHMuMTByYnMubHMsIGNvbFN1bXMpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgU0lNUExJRlkgPSBGQUxTRSkKCiMjIG1ha2UgZGYgZm9yIHBsb3R0aW5nCiMgcmVzcCArIGJ1bGssIHcvIGFuZCB3L28gc3RvY2tzCm1vZC5zb2NzLjJwcy4xMGJycmJzLmRmIDwtIHJiaW5kKG1vZC5zb2NzLmRmLmZ4KCIycHMgdy9vIHN0b2NrIiwgbW9kLnNvY3MuMnBzLjEwYnIubHMsIGMoImZhc3QiLCAic2xvdyIpKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAsbW9kLnNvY3MuZGYuZngoIjJwcyB3LyBzdG9jayIsIG1vZC5zb2NzLjJwcy4xMHJicy5scywgYygiZmFzdCIsICJzbG93IikpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICxkYXRhLmZyYW1lKFNPQyA9IHVubGlzdChsYXBwbHkoY3NvYy4xOS4wXzMwW2l4LjEwXSwgIltbIiwgNCkpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBQTWVjb19kZXB0aCA9IHBhc3RlMCgKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1bmxpc3QobGFwcGx5KGNzb2MuMTkuMF8zMFtpeC4xMF0sICJbWyIsIDEpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiXyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdW5saXN0KGxhcHBseShjc29jLjE5LjBfMzBbaXguMTBdLCAiW1siLCAyKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIi0iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVubGlzdChsYXBwbHkoY3NvYy4xOS4wXzMwW2l4LjEwXSwgIltbIiwgMykpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTW9kZWwgPSAibWVhc3VyZWQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwb29sID0gInRvdGFsIikKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKQojIGJ1bGsgKyBzdG9jaywgdnMuIHJlc3AsIGJ1bGssICsgc3RvY2sKbW9kLnNvY3MuMnBzLjEwYnNyYnMuZGYgPC0gcmJpbmQobW9kLnNvY3MuZGYuZngoIjJwcyBidWxrICsgc3RvY2sgb25seSIsIG1vZC5zb2NzLjJwcy4xMGJzLmxzLCBjKCJmYXN0IiwgInNsb3ciKSkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLG1vZC5zb2NzLmRmLmZ4KCIycHMgYnVsaywgcmVzcCwgKyBzdG9jayIsIG1vZC5zb2NzLjJwcy4xMHJicy5scywgYygiZmFzdCIsICJzbG93IikpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICxkYXRhLmZyYW1lKFNPQyA9IHVubGlzdChsYXBwbHkoY3NvYy4xOS4wXzMwW2l4LjEwXSwgIltbIiwgNCkpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBQTWVjb19kZXB0aCA9IHBhc3RlMCgKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1bmxpc3QobGFwcGx5KGNzb2MuMTkuMF8zMFtpeC4xMF0sICJbWyIsIDEpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiXyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdW5saXN0KGxhcHBseShjc29jLjE5LjBfMzBbaXguMTBdLCAiW1siLCAyKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIi0iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVubGlzdChsYXBwbHkoY3NvYy4xOS4wXzMwW2l4LjEwXSwgIltbIiwgMykpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTW9kZWwgPSAibWVhc3VyZWQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwb29sID0gInRvdGFsIikKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKQoKCiMjIHBsb3QKbW9kLnNvY3MuMnBzLjEwYnJyYnMuZGYgJT4lCiAgbXV0YXRlKFBNID0gc3Vic3RyKFBNZWNvX2RlcHRoLCAxLCAyKSwKICAgICAgICAgZWNvID0gZmFjdG9yKHN1YnN0cihQTWVjb19kZXB0aCwgMywgNCksIGxldmVscyA9IGMoInBwIiwgIndmIiwgInJmIikpKSAlPiUKICBnZ3Bsb3QoLiwgYWVzKHBvb2wsIFNPQywgZmlsbCA9IE1vZGVsKSkgKwogIGdlb21fY29sKHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2UoKSkgKwogIGZhY2V0X2dyaWQocm93cyA9IHZhcnMoZWNvKSwgY29scyA9IHZhcnMoUE0pKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUocGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSkKbW9kLnNvY3MuMnBzLjEwYnNyYnMuZGYgJT4lCiAgbXV0YXRlKFBNID0gc3Vic3RyKFBNZWNvX2RlcHRoLCAxLCAyKSwKICAgICAgICAgZWNvID0gZmFjdG9yKHN1YnN0cihQTWVjb19kZXB0aCwgMywgNCksIGxldmVscyA9IGMoInBwIiwgIndmIiwgInJmIikpKSAlPiUKICBnZ3Bsb3QoLiwgYWVzKHBvb2wsIFNPQywgZmlsbCA9IE1vZGVsKSkgKwogIGdlb21fY29sKHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2UoKSkgKwogIGZhY2V0X2dyaWQocm93cyA9IHZhcnMoZWNvKSwgY29scyA9IHZhcnMoUE0pKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUocGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSkKIyMjIyMKCiMjIyBTdW1tYXJpemUgb3B0aW1pemVkIHBhciBkYXRhIGZvciBwbG90dGluZwojIyBidWxrIDE0YyBvbmx5CiMgMC0xMApwYXJzLmZpdC4ycHMuMTBiLmRmIDwtIHBhci5maXQuZGYuZngobW9kID0gIjJwcyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJzLmZpdCA9IHBhcnMuZml0LjJwcy4xMGIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJzLmkgPSBwYXJzLmkuMnBzW2l4LjEwXSkKIyAjIDIwLTMwCiMgcGFycy5maXQuMnBzLjMwYi5kZiA8LSBwYXIuZml0LmRmLmZ4KG1vZCA9ICIycHMiLAojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFycy5maXQgPSBwYXJzLmZpdC4ycHMuMzBiLAojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFycy5pID0gcGFycy5pLjJwc1tpeC4zMF0pCgojIyByZXNwICsgYnVsayAxNGMKIyAwLTEwCnBhcnMuZml0LjJwcy4xMGJyLmRmIDwtIHBhci5maXQuZGYuZngobW9kID0gIjJwcyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcnMuZml0ID0gcGFycy5maXQuMnBzLjEwYnIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcnMuaSA9IHBhcnMuaS4ycHNbaXguMTBdKQojIDEwLTIwCnBhcnMuZml0LjJwcy4yMGJyLmwuZGYgPC0gcGFyLmZpdC5kZi5meChtb2QgPSAiMnBzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFycy5maXQgPSBwYXJzLmZpdC4ycHMuMjBici5sLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJzLmkgPSBwYXJzLmkuMnBzW2l4LjEwXSkKIyAjIDIwLTMwCiMgcGFycy5maXQuMnBzLjMwYnIuZGYgPC0gcGFyLmZpdC5kZi5meChtb2QgPSAiMnBzIiwKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJzLmZpdCA9IHBhcnMuZml0LjJwcy4zMGJyLAojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcnMuaSA9IHBhcnMuaS4ycHNbaXguMzBdKQoKIyMgYnVsayAxNGMgKyBzdG9ja3MKIyAwLTEwCnBhcnMuZml0LjJwcy4xMGJzLmRmIDwtIHBhci5maXQuZGYuZngobW9kID0gIjJwcyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcnMuZml0ID0gcGFycy5maXQuMnBzLjEwYnMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcnMuaSA9IHBhcnMuaS4ycHNbaXguMTBdKQojICMgMjAtMzAKIyBwYXJzLmZpdC4ycHMuMzBici5kZiA8LSBwYXIuZml0LmRmLmZ4KG1vZCA9ICIycHMiLAojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcnMuZml0ID0gcGFycy5maXQuMnBzLjMwYnIsCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFycy5pID0gcGFycy5pLjJwc1tpeC4zMF0pCgojIyByZXNwLCBidWxrLCBzdG9ja3MKIyAwLTEwCnBhcnMuZml0LjJwcy4xMHJicy5kZiA8LSBwYXIuZml0LmRmLmZ4KG1vZCA9ICIycHMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJzLmZpdCA9IHBhcnMuZml0LjJwcy4xMHJicywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFycy5pID0gcGFycy5pLjJwc1tpeC4xMF0pCiMgMTAtMjAKcGFycy5maXQuMnBzLjIwcmJzLmRmIDwtIHBhci5maXQuZGYuZngobW9kID0gIjJwcyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcnMuZml0ID0gcGFycy5maXQuMnBzLjIwcmJzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJzLmkgPSBwYXJzLmkuMnBzW2l4LjIwXSkKIyB3LyBsYWcKcGFycy5maXQuMnBzLjIwcmJzLmwuZGYgPC0gcGFyLmZpdC5kZi5meChtb2QgPSAiMnBzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFycy5maXQgPSBwYXJzLmZpdC4ycHMuMjByYnMubCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFycy5pID0gcGFycy5pLjJwc1tpeC4yMF0pCiMgIyAyMC0zMAojIHBhcnMuZml0LjJwcy4zMGJyLmRmIDwtIHBhci5maXQuZGYuZngobW9kID0gIjJwcyIsCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFycy5maXQgPSBwYXJzLmZpdC4ycHMuMzBiciwKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJzLmkgPSBwYXJzLmkuMnBzW2l4LjMwXSkKCiMjIyBQYXIgZml0cwpwYXIucGxvdC5meChtb2QgPSAiMnBzIGJ1bGsgMTRjIiwKICAgICAgICAgICAgZGVwdGggPSAiMC0xMCIsCiAgICAgICAgICAgIHBhci5kZiA9IHBhcnMuZml0LjJwcy4xMGIuZGYsCiAgICAgICAgICAgIGluaXRpYWwgPSBGQUxTRSkKcGFyLnBsb3QuZngobW9kID0gIjJwcyByZXNwICsgYnVsayAxNGMiLAogICAgICAgICAgICBkZXB0aCA9ICIwLTEwIiwKICAgICAgICAgICAgcGFyLmRmID0gcGFycy5maXQuMnBzLjEwYnIuZGYsCiAgICAgICAgICAgIGluaXRpYWwgPSBGQUxTRSkKcGFyLnBsb3QuZngobW9kID0gIjJwcyBidWxrIDE0YyArIHN0b2NrcyIsCiAgICAgICAgICAgIGRlcHRoID0gIjAtMTAiLAogICAgICAgICAgICBwYXIuZGYgPSBwYXJzLmZpdC4ycHMuMTBicy5kZiwKICAgICAgICAgICAgaW5pdGlhbCA9IEZBTFNFKQpwYXIucGxvdC5meChtb2QgPSAiMnBzIHJlc3AsIGJ1bGssIHN0b2NrcyIsCiAgICAgICAgICAgIGRlcHRoID0gIjAtMTAiLAogICAgICAgICAgICBwYXIuZGYgPSBwYXJzLmZpdC4ycHMuMTByYnMuZGYsCiAgICAgICAgICAgIGluaXRpYWwgPSBGQUxTRSkKcGFyLnBsb3QuZngobW9kID0gIjJwcyByZXNwLCBidWxrLCBzdG9ja3MiLAogICAgICAgICAgICBkZXB0aCA9ICIxMC0yMCIsCiAgICAgICAgICAgIHBhci5kZiA9IHBhcnMuZml0LjJwcy4yMHJicy5kZiwKICAgICAgICAgICAgaW5pdGlhbCA9IEZBTFNFKQpwYXIucGxvdC5meChtb2QgPSAiMnBzIHJlc3AsIGJ1bGssIHN0b2NrcyIsCiAgICAgICAgICAgIGRlcHRoID0gIjEwLTIwIiwKICAgICAgICAgICAgcGFyLmRmID0gcGFycy5maXQuMnBzLjIwcmJzLmwuZGYsCiAgICAgICAgICAgIGluaXRpYWwgPSBGQUxTRSkKcGFyLnBsb3QuZngobW9kID0gIjJwcyByZXNwLCBidWxrIiwKICAgICAgICAgICAgZGVwdGggPSAiMTAtMjAiLAogICAgICAgICAgICBwYXIuZGYgPSBwYXJzLmZpdC4ycHMuMjBici5sLmRmLAogICAgICAgICAgICBpbml0aWFsID0gRkFMU0UpCiMgcGFyLnBsb3QuZngobW9kID0gIjJwcyBidWxrIDE0YyIsCiMgICAgICAgICAgICAgZGVwdGggPSAiMjAtMzAiLAojICAgICAgICAgICAgIHBhci5kZiA9IHBhcnMuZml0LjJwcy4zMGIuZGYsCiMgICAgICAgICAgICAgaW5pdGlhbCA9IEZBTFNFKQojIHBhci5wbG90LmZ4KG1vZCA9ICIycHMgcmVzcCArIGJ1bGsgMTRjIiwKIyAgICAgICAgICAgICBkZXB0aCA9ICIyMC0zMCIsCiMgICAgICAgICAgICAgcGFyLmRmID0gcGFycy5maXQuMnBzLjMwYnIuZGYsCiMgICAgICAgICAgICAgaW5pdGlhbCA9IEZBTFNFKQoKIyMjIEZpdCBtb2RlbHMgd2l0aCBvcHRpbWl6ZWQgcGFycwojIyBidWxrIDE0QyBvbmx5CiMgMC0xMApUd29wcy4xMGIuZml0cyA8LSBsYXBwbHkoc2VxX2Fsb25nKHBhcnMuZml0LjJwcy4xMGIpLCBmdW5jdGlvbihpKSB7CiAgdHJ5Q2F0Y2goCiAgICBwYXIuZngocGFycy5maXQuMnBzLjEwYltbaV1dLCBpbi5lc3RbaXguMTBdW1tpXV0sIHZlcmJvc2UgPSBGQUxTRSwgbW9kID0gIjJwcyIsIHBhc3MgPSBGQUxTRSksCiAgICBlcnJvciA9IGZ1bmN0aW9uIChlKSB7Y2F0KCJFUlJPUiA6IiwgY29uZGl0aW9uTWVzc2FnZShlKSwgIlxuIil9KQp9KQpuYW1lcyhUd29wcy4xMGIuZml0cykgPC0gbmFtZXMocGFycy5maXQuMnBzLjEwYikKIyAjIDIwLTMwCiMgVHdvcHMuMzBiLmZpdHMgPC0gbGFwcGx5KHNlcV9hbG9uZyhwYXJzLmZpdC4ycHMuMzBiKSwgZnVuY3Rpb24oaSkgewojICAgdHJ5Q2F0Y2goCiMgICAgIHBhci5meChwYXJzLmZpdC4ycHMuMzBiW1tpXV0sIGluLmVzdFtpeC4zMF1bW2ldXSwgdmVyYm9zZSA9IEZBTFNFLCBtb2QgPSAiMnBzIiwgcGFzcyA9IEZBTFNFKSwKIyAgICAgZXJyb3IgPSBmdW5jdGlvbiAoZSkge2NhdCgiRVJST1IgOiIsIGNvbmRpdGlvbk1lc3NhZ2UoZSksICJcbiIpfSkKIyB9KQojIG5hbWVzKFR3b3BzLjMwYi5maXRzKSA8LSBuYW1lcyhwYXJzLmZpdC4ycHMuMzBiKQoKIyMgcmVzcCArIGJ1bGsgMTRDCiMgMC0xMApUd29wcy4xMGJyLmZpdHMgPC0gbGFwcGx5KHNlcV9hbG9uZyhwYXJzLmZpdC4ycHMuMTBiciksIGZ1bmN0aW9uKGkpIHsKICB0cnlDYXRjaCgKICAgIHBhci5meChwYXJzLmZpdC4ycHMuMTBicltbaV1dLCBpbi5lc3RbaXguMTBdW1tpXV0sIHZlcmJvc2UgPSBGQUxTRSwgbW9kID0gIjJwcyIsIHBhc3MgPSBGQUxTRSksCiAgICBlcnJvciA9IGZ1bmN0aW9uIChlKSB7Y2F0KCJFUlJPUiA6IiwgY29uZGl0aW9uTWVzc2FnZShlKSwgIlxuIil9KQp9KQpuYW1lcyhUd29wcy4xMGJyLmZpdHMpIDwtIG5hbWVzKHBhcnMuZml0LjJwcy4xMGJyKQojIDEwLTIwClR3b3BzLjIwYnIubC5maXRzIDwtIGxhcHBseShzZXFfYWxvbmcocGFycy5maXQuMnBzLjIwYnIubCksIGZ1bmN0aW9uKGkpIHsKICB0cnlDYXRjaCgKICAgIHBhci5meChwYXJzLmZpdC4ycHMuMjBici5sW1tpXV0sIGluLmVzdFtpeC4xMF1bW2ldXSwgdmVyYm9zZSA9IEZBTFNFLCBtb2QgPSAiMnBzIiwgcGFzcyA9IEZBTFNFKSwKICAgIGVycm9yID0gZnVuY3Rpb24gKGUpIHtjYXQoIkVSUk9SIDoiLCBjb25kaXRpb25NZXNzYWdlKGUpLCAiXG4iKX0pCn0pCm5hbWVzKFR3b3BzLjIwYnIubC5maXRzKSA8LSBuYW1lcyhwYXJzLmZpdC4ycHMuMjBici5sKQojICMgMjAtMzAKIyBUd29wcy4zMGJyLmZpdHMgPC0gbGFwcGx5KHNlcV9hbG9uZyhwYXJzLmZpdC4ycHMuMzBiciksIGZ1bmN0aW9uKGkpIHsKIyAgIHRyeUNhdGNoKAojICAgICBwYXIuZngocGFycy5maXQuMnBzLjMwYnJbW2ldXSwgaW4uZXN0W2l4LjMwXVtbaV1dLCB2ZXJib3NlID0gRkFMU0UsIG1vZCA9ICIycHMiLCBwYXNzID0gRkFMU0UpLAojICAgICBlcnJvciA9IGZ1bmN0aW9uIChlKSB7Y2F0KCJFUlJPUiA6IiwgY29uZGl0aW9uTWVzc2FnZShlKSwgIlxuIil9KQojIH0pCiMgbmFtZXMoVHdvcHMuMzBici5maXRzKSA8LSBuYW1lcyhwYXJzLmZpdC4ycHMuMzBicikKCiMjIGJ1bGsgMTRDICsgc3RvY2tzCiMgMC0xMApUd29wcy4xMGJzLmZpdHMgPC0gbGFwcGx5KHNlcV9hbG9uZyhwYXJzLmZpdC4ycHMuMTBicyksIGZ1bmN0aW9uKGkpIHsKICB0cnlDYXRjaCgKICAgIHBhci5meChwYXJzLmZpdC4ycHMuMTBic1tbaV1dLCBpbi5lc3RbaXguMTBdW1tpXV0sIHZlcmJvc2UgPSBGQUxTRSwgbW9kID0gIjJwcyIsIHBhc3MgPSBGQUxTRSksCiAgICBlcnJvciA9IGZ1bmN0aW9uIChlKSB7Y2F0KCJFUlJPUiA6IiwgY29uZGl0aW9uTWVzc2FnZShlKSwgIlxuIil9KQp9KQpuYW1lcyhUd29wcy4xMGJzLmZpdHMpIDwtIG5hbWVzKHBhcnMuZml0LjJwcy4xMGJzKQoKIyMgcmVzcCwgYnVsaywgc3RvY2tzCiMgMC0xMApUd29wcy4xMHJicy5maXRzIDwtIGxhcHBseShzZXFfYWxvbmcocGFycy5maXQuMnBzLjEwcmJzKSwgZnVuY3Rpb24oaSkgewogIHRyeUNhdGNoKAogICAgcGFyLmZ4KHBhcnMuZml0LjJwcy4xMHJic1tbaV1dLCBpbi5lc3RbaXguMTBdW1tpXV0sIHZlcmJvc2UgPSBGQUxTRSwgbW9kID0gIjJwcyIsIHBhc3MgPSBGQUxTRSksCiAgICBlcnJvciA9IGZ1bmN0aW9uIChlKSB7Y2F0KCJFUlJPUiA6IiwgY29uZGl0aW9uTWVzc2FnZShlKSwgIlxuIil9KQp9KQpuYW1lcyhUd29wcy4xMHJicy5maXRzKSA8LSBuYW1lcyhwYXJzLmZpdC4ycHMuMTByYnMpCiMgMTAtMjAKVHdvcHMuMjByYnMuZml0cyA8LSBsYXBwbHkoc2VxX2Fsb25nKHBhcnMuZml0LjJwcy4yMHJicyksIGZ1bmN0aW9uKGkpIHsKICB0cnlDYXRjaCgKICAgIHBhci5meChwYXJzLmZpdC4ycHMuMjByYnNbW2ldXSwgaW4uZXN0W2l4LjIwXVtbaV1dLCB2ZXJib3NlID0gRkFMU0UsIG1vZCA9ICIycHMiLCBwYXNzID0gRkFMU0UpLAogICAgZXJyb3IgPSBmdW5jdGlvbiAoZSkge2NhdCgiRVJST1IgOiIsIGNvbmRpdGlvbk1lc3NhZ2UoZSksICJcbiIpfSkKfSkKbmFtZXMoVHdvcHMuMjByYnMuZml0cykgPC0gbmFtZXMocGFycy5maXQuMnBzLjIwcmJzKQoKIyAjIHJlbW92ZSBudWxsIGVudHJpZXMKIyBUd29wcy4xMGIuZml0cyA8LSBGaWx0ZXIoTmVnYXRlKGlzLm51bGwpLCBUd29wcy4xMGIuZml0cykKIyBUd29wcy4zMGIuZml0cyA8LSBGaWx0ZXIoTmVnYXRlKGlzLm51bGwpLCBUd29wcy4zMGIuZml0cykKIyBUd29wcy4xMGJyLmZpdHMgPC0gRmlsdGVyKE5lZ2F0ZShpcy5udWxsKSwgVHdvcHMuMTBici5maXRzKQojIFR3b3BzLjMwYnIuZml0cyA8LSBGaWx0ZXIoTmVnYXRlKGlzLm51bGwpLCBUd29wcy4zMGJyLmZpdHMpCgojIExvb2sgYXQgcm9sZSBvZiByZXNwIGNvbnN0cmFpbnQgaW4gZml0CiMgbGFwcGx5KHNlcV9hbG9uZyhUd29wcy4xMGIuZml0cyksIGZ1bmN0aW9uKGkpIHsKIyAgIEMxNC4ycC5wbG90LmZ4KFR3b3BzLjEwYi5maXRzW1tpXV0sCiMgICAgICAgICAgICAgICAgICBjb24uZGYgPSBjb24uZGYuZngobmFtZXMoVHdvcHMuMTBiLmZpdHMpW2ldKSwgCiMgICAgICAgICAgICAgICAgICBtb2QgPSAiMnBzIGJ1bGsgb25seSIsCiMgICAgICAgICAgICAgICAgICBQTWVjb19kZXB0aCA9IG5hbWVzKFR3b3BzLjEwYi5maXRzKVtpXSkKIyB9KQpsYXBwbHkoc2VxX2Fsb25nKFR3b3BzLjEwYnIuZml0cyksIGZ1bmN0aW9uKGkpIHsKICBDMTQuMnAucGxvdC5meChUd29wcy4xMGJyLmZpdHNbW2ldXSwgCiAgICAgICAgICAgICAgICAgY29uLmRmID0gY29uLmRmLmZ4KG5hbWVzKFR3b3BzLjEwYnIuZml0cylbaV0pLCAKICAgICAgICAgICAgICAgICBtb2QgPSAiMnBzIGJ1bGsgKyByZXNwIiwKICAgICAgICAgICAgICAgICBQTWVjb19kZXB0aCA9IG5hbWVzKFR3b3BzLjEwYnIuZml0cylbaV0pCn0pCiMgbGFwcGx5KHNlcV9hbG9uZyhUd29wcy4xMGJzLmZpdHMpLCBmdW5jdGlvbihpKSB7CiMgICBDMTQuMnAucGxvdC5meChUd29wcy4xMGJzLmZpdHNbW2ldXSwKIyAgICAgICAgICAgICAgICAgIGNvbi5kZiA9IGNvbi5kZi5meChuYW1lcyhUd29wcy4xMGJzLmZpdHMpW2ldKSwgCiMgICAgICAgICAgICAgICAgICBtb2QgPSAiMnBzIGJ1bGsgKyBzdG9jayIsCiMgICAgICAgICAgICAgICAgICBQTWVjb19kZXB0aCA9IG5hbWVzKFR3b3BzLjEwYnMuZml0cylbaV0pCiMgfSkKbGFwcGx5KHNlcV9hbG9uZyhUd29wcy4xMHJicy5maXRzKSwgZnVuY3Rpb24oaSkgewogIEMxNC4ycC5wbG90LmZ4KFR3b3BzLjEwcmJzLmZpdHNbW2ldXSwgCiAgICAgICAgICAgICAgICAgY29uLmRmID0gY29uLmRmLmZ4KG5hbWVzKFR3b3BzLjEwcmJzLmZpdHMpW2ldKSwgCiAgICAgICAgICAgICAgICAgbW9kID0gImJ1bGssIHJlc3AsIHN0b2NrIiwKICAgICAgICAgICAgICAgICBQTWVjb19kZXB0aCA9IG5hbWVzKFR3b3BzLjEwcmJzLmZpdHMpW2ldKQp9KQojIDEwLTIwCmxhcHBseShzZXFfYWxvbmcoVHdvcHMuMjByYnMuZml0cyksIGZ1bmN0aW9uKGkpIHsKICBDMTQuMnAucGxvdC5meChUd29wcy4yMHJicy5maXRzW1tpXV0sIAogICAgICAgICAgICAgICAgIGNvbi5kZiA9IGNvbi5kZi5meChuYW1lcyhUd29wcy4yMHJicy5maXRzKVtpXSksIAogICAgICAgICAgICAgICAgIG1vZCA9ICJidWxrLCByZXNwLCBzdG9jayIsCiAgICAgICAgICAgICAgICAgUE1lY29fZGVwdGggPSBuYW1lcyhUd29wcy4yMHJicy5maXRzKVtpXSkKfSkKIyBsYXBwbHkoc2VxX2Fsb25nKFR3b3BzLjMwYi5maXRzKSwgZnVuY3Rpb24oaSkgewojICAgQzE0LjJwLnBsb3QuZngoVHdvcHMuMzBiLmZpdHNbW2ldXSwKIyAgICAgICAgICAgICAgICAgIGNvbi5kZiA9IGNvbi5kZi5meChuYW1lcyhUd29wcy4zMGIuZml0cylbaV0pLCAKIyAgICAgICAgICAgICAgICAgIG1vZCA9ICIycHMgYnVsayBvbmx5IiwKIyAgICAgICAgICAgICAgICAgIFBNZWNvX2RlcHRoID0gbmFtZXMoVHdvcHMuMzBiLmZpdHMpW2ldKQojIH0pCiMgbGFwcGx5KHNlcV9hbG9uZyhUd29wcy4zMGJyLmZpdHMpLCBmdW5jdGlvbihpKSB7CiMgICBDMTQuMnAucGxvdC5meChUd29wcy4zMGJyLmZpdHNbW2ldXSwgCiMgICAgICAgICAgICAgICAgICBjb24uZGYgPSBjb24uZGYuZngobmFtZXMoVHdvcHMuMzBici5maXRzKVtpXSksIAojICAgICAgICAgICAgICAgICAgbW9kID0gIjJwcyBidWxrICsgcmVzcCIsCiMgICAgICAgICAgICAgICAgICBQTWVjb19kZXB0aCA9IG5hbWVzKFR3b3BzLjMwYnIuZml0cylbaV0pCiMgfSkKCiMjIFNob3cgcm9sZSBvZiByZXNwIGluIGNvbnN0cmFpbmluZyBtb2RlbHMKIyBHUndmIDAtMTAKVHdvcC5maXQucGxvdC5meChUd29wcy4xMGJzLmZpdHNbd2hpY2gobmFtZXMoVHdvcHMuMTBicy5maXRzKSA9PSAiR1J3Zl8wLTEwIildLCAKICAgICAgICAgICAgICAgICAiMnBzIDAtMTBjbSwgYnVsayAxNGMgKyBzdG9jayIsIAogICAgICAgICAgICAgICAgIFR3b3BzLjEwcmJzLmZpdHNbd2hpY2gobmFtZXMoVHdvcHMuMTByYnMuZml0cykgPT0gIkdSd2ZfMC0xMCIpXSwKICAgICAgICAgICAgICAgICAiMnBzIDAtMTBjbSwgcmVzcCAmIGJ1bGsgMTRjICsgc3RvY2siKQojIEJTcmYgMC0xMApUd29wLmZpdC5wbG90LmZ4KFR3b3BzLjEwYnIuZml0c1t3aGljaChuYW1lcyhUd29wcy4xMGJyLmZpdHMpID09ICJCU3JmXzAtMTAiKV0sIAogICAgICAgICAgICAgICAgICIycHMgMC0xMGNtIHcvIHJlc3AiLCAKICAgICAgICAgICAgICAgICBUd29wcy4xMGIuZml0c1t3aGljaChuYW1lcyhUd29wcy4xMGIuZml0cykgPT0gIkJTcmZfMC0xMCIpXSwKICAgICAgICAgICAgICAgICAiMnBzIDAtMTBjbSB3L28gcmVzcCIpClR3b3AuZml0LnBsb3QuZngoVHdvcHMuMTByYnMuZml0c1t3aGljaChuYW1lcyhUd29wcy4xMHJicy5maXRzKSA9PSAiQlNyZl8wLTEwIildLAogICAgICAgICAgICAgICAgICIycHMgMC0xMGNtIHcvIHJlc3AsIGJ1bGssIHN0b2NrcyIsCiAgICAgICAgICAgICAgICAgVHdvcHMuMTBicy5maXRzW3doaWNoKG5hbWVzKFR3b3BzLjEwYnMuZml0cykgPT0gIkJTcmZfMC0xMCIpXSwKICAgICAgICAgICAgICAgICAiMnBzIDAtMTBjbSB3L28gcmVzcCAoYnVsayArIHN0b2NrcyBvbmx5KSIpClR3b3AuZml0LnBsb3QuZngoVHdvcHMuMTByYnMuZml0c1t3aGljaChuYW1lcyhUd29wcy4xMHJicy5maXRzKSA9PSAiQlN3Zl8xMC0yMCIpXSwKICAgICAgICAgICAgICAgICAiQmFzYWx0L2Nvb2wgMTAtMjAiLAogICAgICAgICAgICAgICAgIFR3b3BzLjEwcmJzLmZpdHNbd2hpY2gobmFtZXMoVHdvcHMuMTByYnMuZml0cykgPT0gIkdSd2ZfMTAtMjAiKV0sCiAgICAgICAgICAgICAgICAgIkdyYW5pdGUvY29vbCAxMC0yMCIpCgojIGNvbXBhcmUgcmVzcCArIGJ1bGsgZml0cyB3LyBhbmQgdy9vIHN0b2NrcwpUd29wLmZpdC5wbG90LmZ4KFR3b3BzLjEwcmJzLmZpdHMsIAogICAgICAgICAgICAgICAgICIycHMgMC0xMGNtIHcvIHJlc3AsIGJ1bGssIHN0b2NrcyIsIAogICAgICAgICAgICAgICAgIFR3b3BzLjEwYnIuZml0cywKICAgICAgICAgICAgICAgICAiMnBzIDAtMTBjbSB3LyByZXNwICsgYnVsaywgbm8gc3RvY2siKQojIGNvbXBhcmUgcmVzcCArIGJ1bGsgZml0cyB3LyBhbmQgdy9vIHN0b2NrcwpUd29wLmZpdC5wbG90LmZ4KFR3b3BzLjEwYnMuZml0cywgCiAgICAgICAgICAgICAgICAgIjJwcyAwLTEwY20sIGJ1bGsgMTRjICsgc3RvY2siLCAKICAgICAgICAgICAgICAgICBUd29wcy4xMHJicy5maXRzLAogICAgICAgICAgICAgICAgICIycHMgMC0xMGNtLCByZXNwICYgYnVsayAxNGMgKyBzdG9jayIpCiMgY29tcGFyZSBCU3dmIGFuZCBHUndmIDEwLTIwCkJTR1J3ZjIwLmNvbi5kZiA8LSBjYmluZChyYmluZChjb24uZGYuZngoIkJTd2ZfMTAtMjAiKSwgY29uLmRmLmZ4KCJHUndmXzEwLTIwIikpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcG0gPSBmYWN0b3IocmVwKGMoImJhc2FsdCIsICJncmFuaXRlIiksIGVhY2ggPSBjKDExKSkpKQpCU0dSd2YyMC5jb24uZGYgPC0gQlNHUndmMjAuY29uLmRmWy13aGljaChCU0dSd2YyMC5jb24uZGYkWWVhciA9PSAyMDA5LjUpLCBdCkFOR1J3ZjIwLmNvbi5kZiA8LSBjYmluZChyYmluZChjb24uZGYuZngoIkJTd2ZfMTAtMjAiKSwgY29uLmRmLmZ4KCJHUndmXzEwLTIwIikpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcG0gPSBmYWN0b3IocmVwKGMoImJhc2FsdCIsICJncmFuaXRlIiksIGVhY2ggPSBjKDExKSkpKQpCU0dSd2YyMC5jb24uZGYgPC0gQlNHUndmMjAuY29uLmRmWy13aGljaChCU0dSd2YyMC5jb24uZGYkWWVhciA9PSAyMDA5LjUpLCBdCmF0bS4xNGMyIDwtIFR3b3BzLjIwcmJzLmZpdHMkYEJTd2ZfMTAtMjBgW1R3b3BzLjIwcmJzLmZpdHMkYEJTd2ZfMTAtMjBgJHllYXJzID49IDE5NTAgJiBUd29wcy4yMHJicy5maXRzJGBCU3dmXzEwLTIwYCRwb29sID09ICJhdG0iLCBdCiMgcGxvdApwIDwtIHJiaW5kKFR3b3BzLjIwcmJzLmZpdHMkYEJTd2ZfMTAtMjBgLAogICAgICBUd29wcy4yMHJicy5maXRzJGBHUndmXzEwLTIwYCkgJT4lCiAgbXV0YXRlKHBtID0gcmVwKGMoImJhc2FsdCIsICJncmFuaXRlIiksIAogICAgICAgICAgICAgICAgICBlYWNoID0gbnJvdyhUd29wcy4yMHJicy5maXRzJGBCU3dmXzEwLTIwYCkpKSAlPiUKICBmaWx0ZXIocG9vbCA9PSAiYnVsayBDIiB8IHBvb2wgPT0gInJlc3BpcmF0aW9uIikgJT4lCiAgZ2dwbG90KC4sIGFlcyh5ZWFycywgZDE0QykpICsKICBnZW9tX3BhdGgoZGF0YSA9IGF0bS4xNGMyKSArCiAgZ2VvbV9wYXRoKGFlcyhsaW5ldHlwZSA9IHBvb2wsIGNvbG9yID0gcG0pKSArCiAgZ2VvbV9wb2ludChkYXRhID0gQlNHUndmMjAuY29uLmRmLCAKICAgICAgICAgICAgIGFlcyhZZWFyLCBkMTRjLCBjb2xvciA9IHBtLCBzaGFwZSA9IHBvb2wpLCAKICAgICAgICAgICAgIHNpemUgPSAyLjUsCiAgICAgICAgICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMSkpICsKICBzY2FsZV9jb2xvcl9tYW51YWwoCiAgICBuYW1lID0gIlBhcmVudCBtYXRlcmlhbCIsCiAgICB2YWx1ZXMgPSBjKCJiYXNhbHQiID0gInJlZCIsCiAgICAgICAgICAgICAgICJncmFuaXRlIiA9ICJkYXJrZ3JheSIpKSArCiAgc2NhbGVfc2hhcGVfbWFudWFsKAogICAgbmFtZSA9ICIiLAogICAgdmFsdWVzID0gYygiYnVsayBDIiA9IDE2LAogICAgICAgICAgICAgICAicmVzcGlyYXRpb24iID0gMSkpICsKICBzY2FsZV9saW5ldHlwZV9tYW51YWwoCiAgIG5hbWUgPSAiUG9vbCIsCiAgIHZhbHVlcyA9IGMoImJ1bGsgQyIgPSAxLAogICAgICAgICAgICAgICJyZXNwaXJhdGlvbiIgPSAyKSkgKwogIHNjYWxlX3hfY29udGludW91cyhsaW1pdHMgPSBjKDE5NTAsIDIwMjIpKSArCiAgeGxhYigiWWVhciIpICsKICB5bGFiKGV4cHJlc3Npb24oJycqRGVsdGEqJydeMTQqJ0MgKOKAsCknKSkgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKHBhbmVsLmdyaWQgPSBlbGVtZW50X2JsYW5rKCkpCmdnc2F2ZSgic3JhLjJwcy5CU0dSd2YyMC5wZGYiLCBwLCBkcGkgPSAzMDAsIHdpZHRoID0gNiwgaGVpZ2h0ID0gNSwgdW5pdHMgPSAiaW4iKQojIGNvbXBhcmUgcmVzcCArIGJ1bGsgZml0cyB3LyBhbmQgdy9vIHN0b2NrcwpUd29wLmZpdC5wbG90LmZ4KFR3b3BzLjIwYnIubC5maXRzLCAKICAgICAgICAgICAgICAgICAiMnBzIDAtMTBjbSwgYnVsayAxNGMgKyBzdG9jayIsIAogICAgICAgICAgICAgICAgIFR3b3BzLjIwcmJzLmZpdHMsCiAgICAgICAgICAgICAgICAgIjJwcyAwLTEwY20sIHJlc3AgJiBidWxrIDE0YyArIHN0b2NrIikKIyMjIyMKCiMgYWdlcyBhbmQgdHJhbnNpdCB0aW1lcwojIyMjIwojIDJwcwpTQS4ycHMuMjAucmJzLmxzIDwtIGxhcHBseShzZXFfYWxvbmcocGFycy5maXQuMnBzLjIwcmJzKSwgZnVuY3Rpb24oaSkgewogIGtzIDwtIHBhcnMuZml0LjJwcy4yMHJic1tbaV1dWzE6Ml0KICB0YyA8LSBwYXJzLmZpdC4ycHMuMjByYnNbW2ldXVszXQogIEluIDwtIGluLmVzdFtpeC4yMF1bW2ldXQogIEEgPC0gZGlhZygta3MpCiAgQVsyLCAxXSA8LSB0YyAqIGtzWzFdCiAgcmV0dXJuKHN5c3RlbUFnZShBID0gQSwgdSA9IGMoSW4sIDApKSkKfSkKbmFtZXMoU0EuMnBzLjIwLnJicy5scykgPC0gbmFtZXMocGFycy5maXQuMnBzLjIwcmJzKQpsYXBwbHkoU0EuMnBzLjIwLnJicy5scywgIltbIiwgMSkKCiMjIFRyYW5zaXQgdGltZQojIDJwcwpUVC4ycHMuMjAucmJzLmxzIDwtIGxhcHBseShzZXFfYWxvbmcocGFycy5maXQuMnBzLjIwcmJzKSwgZnVuY3Rpb24oaSkgewogIGtzIDwtIHBhcnMuZml0LjJwcy4yMHJic1tbaV1dWzE6Ml0KICB0YyA8LSBwYXJzLmZpdC4ycHMuMjByYnNbW2ldXVszXQogIEluIDwtIGluLmVzdFtpeC4yMF1bW2ldXQogIEEgPC0gZGlhZygta3MpCiAgQVsyLCAxXSA8LSB0YyAqIGtzWzFdCiAgcmV0dXJuKHRyYW5zaXRUaW1lKEEgPSBBLCB1ID0gYyhJbiwgMCkpKQp9KQpuYW1lcyhUVC4ycHMuMjAucmJzLmxzKSA8LSBuYW1lcyhwYXJzLmZpdC4ycHMuMjByYnMpCmxhcHBseShUVC4ycHMuMjAucmJzLmxzLCAiW1siLCAxKQojIDAtMTAKVFQuTUEuMnBzLjEwLnJicy5scyA8LSBsYXBwbHkoc2VxX2Fsb25nKHBhcnMuZml0LjJwcy4xMHJicyksIGZ1bmN0aW9uKGkpIHsKICBrcyA8LSBwYXJzLmZpdC4ycHMuMTByYnNbW2ldXVsxOjJdCiAgdGMgPC0gcGFycy5maXQuMnBzLjEwcmJzW1tpXV1bM10KICBJbiA8LSBpbi5lc3RbaXguMTBdW1tpXV0KICBBIDwtIGRpYWcoLWtzKQogIEFbMiwgMV0gPC0gdGMgKiBrc1sxXQogIFRUIDwtIHRyYW5zaXRUaW1lKEEgPSBBLCB1ID0gYyhJbiwgMCkpCiAgQWdlIDwtIHN5c3RlbUFnZShBID0gQSwgdSA9IGMoSW4sIDApKQogIHJldHVybihsaXN0KFRUID0gVFQkbWVhblRyYW5zaXRUaW1lLCBBZ2UgPSBBZ2UkbWVhblN5c3RlbUFnZSkpCn0pCm5hbWVzKFRULk1BLjJwcy4xMC5yYnMubHMpIDwtIG5hbWVzKHBhcnMuZml0LjJwcy4xMHJicykKbGFwcGx5KFRULk1BLjJwcy4xMC5yYnMubHMsIHVubGlzdCkKIyAKYWdlRC4ycHMuMTAucmJzLmxzIDwtIGxhcHBseShzZXFfYWxvbmcocGFycy5maXQuMnBzLjEwcmJzKSwgZnVuY3Rpb24oaSkgewogIGtzIDwtIHBhcnMuZml0LjJwcy4xMHJic1tbaV1dWzE6Ml0KICB0YyA8LSBwYXJzLmZpdC4ycHMuMTByYnNbW2ldXVszXQogIEluIDwtIGluLmVzdFtpeC4xMF1bW2ldXQogIEEgPC0gZGlhZygta3MpCiAgQVsyLCAxXSA8LSB0YyAqIGtzWzFdCiAgcmV0dXJuKHN5c3RlbUFnZShBID0gQSwgdSA9IGMoSW4sIDApKSkKfSkKbmFtZXMoYWdlRC4ycHMuMTAucmJzLmxzKSA8LSBuYW1lcyhwYXJzLmZpdC4ycHMuMTByYnMpCmBgYAoKYGBge3IgbW9kRml0LTJwLWNvbXBhcmlzb259CiMgY29tcGFyZSBvdXRwdXQgb2YgMnBwIGFuZCAycHMgbW9kZWwgZml0cwptZXJnZShzc3IuMnBwLmRmLCBzc3IuMnBzLmRmLCBieSA9ICJQTWVjb19kZXB0aCIsIHN1ZmZpeGVzID0gYygiXzJwcCIsICJfMnBzIikpICU+JQogIG11dGF0ZShzc3JfMnBwID0gcm91bmQoc3NyXzJwcCwgMSksCiAgICAgICAgIHNzcl8ycHMgPSByb3VuZChzc3JfMnBzLCAxKSwKICAgICAgICAgZGlmID0gc3NyXzJwcCAtIHNzcl8ycHMpCm1lcmdlKHZhcl9tcy4ycHAuZGYsCiAgICAgIHZhcl9tcy4ycHMuZGYsCiAgICAgIGJ5ID0gYygiUE1lY29fZGVwdGgiLCAidmFyIiksCiAgICAgIHN1ZmZpeGVzID0gYygiXzJwcCIsICJfMnBzIikpICU+JQogIG11dGF0ZSh2YXJfbXNfMnBwID0gcm91bmQodmFyX21zXzJwcCwgNCksCiAgICAgICAgIHZhcl9tc18ycHMgPSByb3VuZCh2YXJfbXNfMnBzLCA0KSwKICAgICAgICAgZGlmID0gdmFyX21zXzJwcCAtIHZhcl9tc18ycHMpCgojIyBQbG90CiMgU1NSLCBQTQpyYmluZChzc3IuMnBwLmRmLCBzc3IuMnBzLmRmKSAlPiUKICBtdXRhdGUobW9kID0gcmVwKGMoIjJwcCIsICIycHMiKSwgZWFjaCA9IG5yb3coc3NyLjJwcC5kZikpLAogICAgICAgICBQTSA9IHN1YnN0cihQTWVjb19kZXB0aCwgMSwgMiksCiAgICAgICAgIGVjbyA9IHN1YnN0cihQTWVjb19kZXB0aCwgMywgNCkpICU+JQogIGdyb3VwX2J5KFBNLCBtb2QpICU+JQogIHN1bW1hcml6ZShtZWFuLnNzciA9IG1lYW4oc3NyKSwgc2QgPSBzZChzc3IpKSAlPiUKICBtdXRhdGUoZXJyX3UgPSBtZWFuLnNzciArIHNkL3NxcnQoMyksCiAgICAgICAgIGVycl9sID0gbWVhbi5zc3IgLSBzZC9zcXJ0KDMpKSAlPiUKICBnZ3Bsb3QoLiwgYWVzKG1vZCwgbWVhbi5zc3IsIGZpbGwgPSBQTSkpICsKICBnZW9tX2NvbChwb3NpdGlvbiA9ICJkb2RnZSIpICsKICBnZW9tX2Vycm9yYmFyKAogICAgYWVzKHltYXggPSBlcnJfdSwgeW1pbiA9IGVycl9sKSwgCiAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gLjkpLAogICAgd2lkdGggPSAuMykgKwogIHNjYWxlX2ZpbGxfbWFudWFsKG5hbWUgPSAiUGFyZW50IG1hdGVyaWFsIiwKICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCJBTiIgPSAiYW5kZXNpdGUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkJTIiA9ICJiYXNhbHQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkdSIiA9ICJncmFuaXRlIiksCiAgICAgICAgICAgICAgICAgICAgdmFsdWVzID0gYygiQU4iID0gImJsdWUiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJCUyIgPSAicmVkIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiR1IiID0gImRhcmtncmF5IikpICsKICBmYWNldF93cmFwKC4gfiBQTSkgKwogIGdndGl0bGUoIlNTUiAyLXBvb2wgbW9kZWxzIDAtMTAgY20iKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUocGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSkKIyBTU1IsIGVjbwpyYmluZChzc3IuMnBwLmRmLCBzc3IuMnBzLmRmKSAlPiUKICBtdXRhdGUobW9kID0gcmVwKGMoIjJwcCIsICIycHMiKSwgZWFjaCA9IG5yb3coc3NyLjJwcC5kZikpLAogICAgICAgICBQTSA9IHN1YnN0cihQTWVjb19kZXB0aCwgMSwgMiksCiAgICAgICAgIGVjbyA9IHN1YnN0cihQTWVjb19kZXB0aCwgMywgNCkpICU+JQogIGdyb3VwX2J5KGVjbywgbW9kKSAlPiUKICBzdW1tYXJpemUobWVhbi5zc3IgPSBtZWFuKHNzciksIHNkID0gc2Qoc3NyKSkgJT4lCiAgbXV0YXRlKGVycl91ID0gbWVhbi5zc3IgKyBzZC9zcXJ0KDMpLAogICAgICAgICBlcnJfbCA9IG1lYW4uc3NyIC0gc2Qvc3FydCgzKSkgJT4lCiAgZ2dwbG90KC4sIGFlcyhtb2QsIG1lYW4uc3NyLCBmaWxsID0gZWNvKSkgKwogIGdlb21fY29sKHBvc2l0aW9uID0gImRvZGdlIikgKwogIGdlb21fZXJyb3JiYXIoCiAgICBhZXMoeW1heCA9IGVycl91LCB5bWluID0gZXJyX2wpLCAKICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAuOSksCiAgICB3aWR0aCA9IC4zKSArCiAgZmFjZXRfd3JhcCguIH4gZWNvKSArCiAgZ2d0aXRsZSgiU1NSIDItcG9vbCBtb2RlbHMgMC0xMCBjbSAoZWNvKSIpICsKICB0aGVtZV9idygpICsKICB0aGVtZShwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpKQoKIyB2YXJfbXMsIFBNCnJiaW5kKHZhcl9tcy4ycHAuZGYsIHZhcl9tcy4ycHMuZGYpICU+JQogIG11dGF0ZShtb2QgPSByZXAoYygiMnBwIiwgIjJwcyIpLCBlYWNoID0gbnJvdyh2YXJfbXMuMnBwLmRmKSksCiAgICAgICAgIFBNID0gc3Vic3RyKFBNZWNvX2RlcHRoLCAxLCAyKSwKICAgICAgICAgZWNvID0gc3Vic3RyKFBNZWNvX2RlcHRoLCAzLCA0KSkgJT4lCiAgZ3JvdXBfYnkodmFyLCBQTSwgbW9kKSAlPiUKICBzdW1tYXJpemUobWVhbi52YXJfbXMgPSBtZWFuKHZhcl9tcyksIHNkID0gc2QodmFyX21zKSkgJT4lCiAgbXV0YXRlKGVycl91ID0gbWVhbi52YXJfbXMgKyBzZC9zcXJ0KDMpLAogICAgICAgICBlcnJfbCA9IG1lYW4udmFyX21zIC0gc2Qvc3FydCgzKSkgJT4lCiAgZ2dwbG90KC4sIGFlcyhtb2QsIG1lYW4udmFyX21zLCBmaWxsID0gUE0pKSArCiAgZ2VvbV9jb2wocG9zaXRpb24gPSAiZG9kZ2UiKSArCiAgZ2VvbV9lcnJvcmJhcigKICAgIGFlcyh5bWF4ID0gZXJyX3UsIHltaW4gPSBlcnJfbCksIAogICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IC45KSwKICAgIHdpZHRoID0gLjMpICsKICBzY2FsZV9maWxsX21hbnVhbChuYW1lID0gIlBhcmVudCBtYXRlcmlhbCIsCiAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiQU4iID0gImFuZGVzaXRlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJCUyIgPSAiYmFzYWx0IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJHUiIgPSAiZ3Jhbml0ZSIpLAogICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9IGMoIkFOIiA9ICJibHVlIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQlMiID0gInJlZCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkdSIiA9ICJkYXJrZ3JheSIpKSArCiAgZmFjZXRfd3JhcCguIH4gdmFyLCBzY2FsZXMgPSAiZnJlZSIpICsKICBnZ3RpdGxlKCJSZXNpZHVhbCBlcnJvciAyLXBvb2wgbW9kZWxzIDAtMTAgY20iKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUocGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSkKIyB2YXJfbXMsIGVjbwpyYmluZCh2YXJfbXMuMnBwLmRmLCB2YXJfbXMuMnBzLmRmKSAlPiUKICBtdXRhdGUobW9kID0gcmVwKGMoIjJwcCIsICIycHMiKSwgZWFjaCA9IG5yb3codmFyX21zLjJwcC5kZikpLAogICAgICAgICBQTSA9IHN1YnN0cihQTWVjb19kZXB0aCwgMSwgMiksCiAgICAgICAgIGVjbyA9IHN1YnN0cihQTWVjb19kZXB0aCwgMywgNCkpICU+JQogIGdyb3VwX2J5KHZhciwgZWNvLCBtb2QpICU+JQogIHN1bW1hcml6ZShtZWFuLnZhcl9tcyA9IG1lYW4odmFyX21zKSwgc2QgPSBzZCh2YXJfbXMpKSAlPiUKICBtdXRhdGUoZXJyX3UgPSBtZWFuLnZhcl9tcyArIHNkL3NxcnQoMyksCiAgICAgICAgIGVycl9sID0gbWVhbi52YXJfbXMgLSBzZC9zcXJ0KDMpKSAlPiUKICBnZ3Bsb3QoLiwgYWVzKG1vZCwgbWVhbi52YXJfbXMsIGZpbGwgPSBlY28pKSArCiAgZ2VvbV9jb2wocG9zaXRpb24gPSAiZG9kZ2UiKSArCiAgZ2VvbV9lcnJvcmJhcigKICAgIGFlcyh5bWF4ID0gZXJyX3UsIHltaW4gPSBlcnJfbCksIAogICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IC45KSwKICAgIHdpZHRoID0gLjMpICsKICBmYWNldF93cmFwKC4gfiB2YXIsIHNjYWxlcyA9ICJmcmVlIikgKwogIGdndGl0bGUoIlJlc2lkdWFsIGVycm9yIDItcG9vbCBtb2RlbHMgMC0xMCBjbSIpICsKICB0aGVtZV9idygpICsKICB0aGVtZShwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpKQpgYGAKCmBgYHtyIGFnZXMtdHQtbW9kRml0fQojIyBTeXN0ZW0gYWdlCiMgMnBwClNBLjJwcC5scyA8LSBsYXBwbHkoc2VxX2Fsb25nKHBhcnMuZml0LjJwcCksIGZ1bmN0aW9uKGkpIHsKICBrcyA8LSBwYXJzLmZpdC4ycHBbW2ldXVsxOjJdCiAgZ2FtIDwtIHBhcnMuZml0LjJwcFtbaV1dWzNdCiAgSW4gPC0gaW4uZml0LjJwcFtbaV1dCiAgcmV0dXJuKHN5c3RlbUFnZSgsIHUgPSBJbikpCn0pCm5hbWVzKFNBLjJwcC5scykgPC0gbmFtZXMocGFycy5maXQuMnBwKQojIDJwcCBnYW0gPSBbLjUsIC45NV0KU0EuMnBwLnAzLjUuOTUubHMgPC0gbGFwcGx5KHNlcV9hbG9uZyhwYXJzLmZpdC4ycHAucDMuNS45NSksIGZ1bmN0aW9uKGkpIHsKICBrcyA8LSBwYXJzLmZpdC4ycHAucDMuNS45NVtbaV1dWzE6Ml0KICBnYW0gPC0gcGFycy5maXQuMnBwLnAzLjUuOTVbW2ldXVszXQogIEluIDwtIGluLmZpdC4ycHAucDMuNS45NVtbaV1dCiAgcmV0dXJuKHN5c3RlbUFnZShBID0gLTEgKiBkaWFnKGtzKSwgdSA9IGMoSW4gKiBnYW0sIEluICogKDEgLSBnYW0pKSkpCn0pCm5hbWVzKFNBLjJwcC5wMy41Ljk1LmxzKSA8LSBuYW1lcyhwYXJzLmZpdC4ycHAucDMuNS45NSkKIyAycHMKU0EuMnBzLmxzIDwtIGxhcHBseShzZXFfYWxvbmcocGFycy5maXQuMnBzKSwgZnVuY3Rpb24oaSkgewogIGtzIDwtIHBhcnMuZml0LjJwc1tbaV1dWzE6Ml0KICBnYW0gPC0gcGFycy5maXQuMnBzW1tpXV1bM10KICBJbiA8LSBpbi5maXQuMnBzW1tpXV0KICByZXR1cm4oc3lzdGVtQWdlKEEgPSAtMSAqIGRpYWcoa3MpLCB1ID0gYyhJbiAqIGdhbSwgSW4gKiAoMSAtIGdhbSkpKSkKfSkKbmFtZXMoU0EuMnBzLmxzKSA8LSBuYW1lcyhwYXJzLmZpdC4ycHMpCgojIyBUcmFuc2l0IHRpbWUKIyAycHAKVFQuMnBwLmxzIDwtIGxhcHBseShzZXFfYWxvbmcocGFycy5maXQuMnBwKSwgZnVuY3Rpb24oaSkgewogIGtzIDwtIHBhcnMuZml0LjJwcFtbaV1dWzE6Ml0KICBnYW0gPC0gcGFycy5maXQuMnBwW1tpXV1bM10KICBJbiA8LSBpbi5maXQuMnBwW1tpXV0KICByZXR1cm4odHJhbnNpdFRpbWUoQSA9IC0xICogZGlhZyhrcyksIHUgPSBjKEluICogZ2FtLCBJbiAqICgxIC0gZ2FtKSkpKQp9KQpuYW1lcyhUVC4ycHAubHMpIDwtIG5hbWVzKHBhcnMuZml0LjJwcCkKIyAycHAgZ2FtID0gWy41LCAuOTVdClRULjJwcC5wMy41Ljk1LmxzIDwtIGxhcHBseShzZXFfYWxvbmcocGFycy5maXQuMnBwLnAzLjUuOTUpLCBmdW5jdGlvbihpKSB7CiAga3MgPC0gcGFycy5maXQuMnBwLnAzLjUuOTVbW2ldXVsxOjJdCiAgZ2FtIDwtIHBhcnMuZml0LjJwcC5wMy41Ljk1W1tpXV1bM10KICBJbiA8LSBpbi5maXQuMnBwLnAzLjUuOTVbW2ldXQogIHJldHVybih0cmFuc2l0VGltZShBID0gLTEgKiBkaWFnKGtzKSwgdSA9IGMoSW4gKiBnYW0sIEluICogKDEgLSBnYW0pKSkpCn0pCm5hbWVzKFRULjJwcC5wMy41Ljk1LmxzKSA8LSBuYW1lcyhwYXJzLmZpdC4ycHAucDMuNS45NSkKIyAycHMKVFQuMnBzLmxzIDwtIGxhcHBseShzZXFfYWxvbmcocGFycy5maXQuMnBzKSwgZnVuY3Rpb24oaSkgewogIGtzIDwtIHBhcnMuZml0LjJwc1tbaV1dWzE6Ml0KICBnYW0gPC0gcGFycy5maXQuMnBzW1tpXV1bM10KICBJbiA8LSBpbi5maXQuMnBzW1tpXV0KICByZXR1cm4odHJhbnNpdFRpbWUoQSA9IC0xICogZGlhZyhrcyksIHUgPSBjKEluICogZ2FtLCBJbiAqICgxIC0gZ2FtKSkpKQp9KQpuYW1lcyhUVC4ycHMubHMpIDwtIG5hbWVzKHBhcnMuZml0LjJwcykKYGBgCgpgYGB7ciBTQS1UVC1jb21wfQojIGNvbXBhcmUgYWdlcyBhbmQgdHJhbnNpdCB0aW1lcyBhbW9uZyB0aGUgdHdvIG1vZGVsIHN0cnVjdHVyZXMKU0EuMnAubHMgPC0gbGlzdChTQS4ycHAubHMsIFNBLjJwcy5scywgU0EuMnBwLnAzLjUuOTUubHMpClNBLmRmIDwtIGJpbmRfcm93cygKICBsYXBwbHkoU0EuMnAubHMsIGZ1bmN0aW9uKGxzKSB7CiAgICBsYXBwbHkoc2VxX2Fsb25nKGxzKSwgZnVuY3Rpb24oaSkgewogICAgICBkYXRhLmZyYW1lKGFnZSA9IGMobHNbW2ldXVtbIm1lYW5TeXN0ZW1BZ2UiXV0sCiAgICAgICAgICAgICAgICAgICAgICAgICBsc1tbaV1dW1sibWVhblBvb2xBZ2UiXV0pLAogICAgICAgICAgICAgICAgIGNvbXBvbmVudCA9IGMoInN5c3RlbSIsICJmYXN0IHBvb2wiLCAic2xvdyBwb29sIikpCiAgICB9KQogIH0pCikKU0EuZGYkUE1lY29fZGVwdGggPC0gcmVwKG5hbWVzKFNBLjJwcC5scyksIGVhY2ggPSAzLCB0aW1lcyA9IGxlbmd0aChTQS4ycC5scykpClNBLmRmJE1vZGVsIDwtIHJlcChjKCIycHAiLCAiMnBzIiwgIjJwcCBbLjUsIC45NV0iKSwgZWFjaCA9IDI3KQpUVC4ycC5scyA8LSBsaXN0KFRULjJwcC5scywgVFQuMnBzLmxzLCBUVC4ycHAucDMuNS45NS5scykKVFQuZGYgPC0gYmluZF9yb3dzKAogIGxhcHBseShUVC4ycC5scywgZnVuY3Rpb24obHMpIHsKICAgIGxhcHBseShzZXFfYWxvbmcobHMpLCBmdW5jdGlvbihpKSB7CiAgICAgZGF0YS5mcmFtZShhZ2UgPSBsc1tbaV1dW1sibWVhblRyYW5zaXRUaW1lIl1dLAogICAgICAgICAgICAgICAgY29tcG9uZW50ID0gInRyYW5zaXQiKQogICAgfSkKICB9KQopClRULmRmJFBNZWNvX2RlcHRoIDwtIHJlcChuYW1lcyhUVC4ycHAubHMpLCB0aW1lcyA9IGxlbmd0aChUVC4ycC5scykpClRULmRmJE1vZGVsIDwtIHJlcChjKCIycHAiLCAiMnBzIiwgIjJwcCBbLjUsIC45NV0iKSwgZWFjaCA9IDkpClNBLlRULmRmIDwtIHJiaW5kKFNBLmRmLCBUVC5kZikKU0EuVFQuZGYkUE0gPC0gc3Vic3RyKFNBLlRULmRmJFBNZWNvX2RlcHRoLCBzdGFydCA9IDEsIHN0b3AgPSAyKQpTQS5UVC5kZiRlY28gPC0gc3Vic3RyKFNBLlRULmRmJFBNZWNvX2RlcHRoLCBzdGFydCA9IDMsIHN0b3AgPSA0KQoKIyMgUGxvdCBhZ2VzIGFuZCB0cmFuc2l0IHRpbWVzCiMgYnkgUE0KU0EuVFQuZGYgJT4lCiAgc2VsZWN0KCFjKFBNZWNvX2RlcHRoLCBlY28pKSAlPiUKICBncm91cF9ieShjb21wb25lbnQsIFBNLCBNb2RlbCkgJT4lCiAgc3VtbWFyaXplX2FsbChsaXN0KG1lYW5fYWdlID0gbWVhbiwgc2QgPSBzZCkpICU+JQogIG11dGF0ZShlcnJfdSA9IG1lYW5fYWdlICsgc2QsCiAgICAgICAgIGVycl9sID0gbWVhbl9hZ2UgLSBzZCkgJT4lCiAgZ2dwbG90KC4sIGFlcyhNb2RlbCwgbWVhbl9hZ2UsIGZpbGwgPSBQTSkpICsKICBnZW9tX2NvbChwb3NpdGlvbiA9ICJkb2RnZSIpICsKICAjIGdlb21fZXJyb3JiYXIoCiAgIyAgIGFlcyh5bWF4ID0gZXJyX3UsIHltaW4gPSBlcnJfbCksIAogICMgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gLjkpLAogICMgICB3aWR0aCA9IC4zKSArCiAgc2NhbGVfZmlsbF9tYW51YWwobmFtZSA9ICJQYXJlbnQgbWF0ZXJpYWwiLAogICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIkFOIiA9ICJhbmRlc2l0ZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQlMiID0gImJhc2FsdCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiR1IiID0gImdyYW5pdGUiKSwKICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSBjKCJBTiIgPSAiYmx1ZSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkJTIiA9ICJyZWQiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJHUiIgPSAiZGFya2dyYXkiKSkgKwogIGZhY2V0X3dyYXAoLiB+IGNvbXBvbmVudCwgc2NhbGVzID0gImZyZWUiKSArCiAgeWxhYigibWVhbiBhZ2UiKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUocGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSkKIyBieSBlY28KU0EuVFQuZGYgJT4lCiAgc2VsZWN0KCFjKFBNZWNvX2RlcHRoLCBQTSkpICU+JQogIGdyb3VwX2J5KGNvbXBvbmVudCwgZWNvLCBNb2RlbCkgJT4lCiAgc3VtbWFyaXplX2FsbChsaXN0KG1lYW5fYWdlID0gbWVhbiwgc2QgPSBzZCkpICU+JQogIG11dGF0ZShlcnJfdSA9IG1lYW5fYWdlICsgc2QsCiAgICAgICAgIGVycl9sID0gbWVhbl9hZ2UgLSBzZCkgJT4lCiAgZ2dwbG90KC4sIGFlcyhNb2RlbCwgbWVhbl9hZ2UsIGZpbGwgPSBlY28pKSArCiAgZ2VvbV9jb2wocG9zaXRpb24gPSAiZG9kZ2UiKSArCiAgIyBnZW9tX2Vycm9yYmFyKAogICMgICBhZXMoeW1heCA9IGVycl91LCB5bWluID0gZXJyX2wpLAogICMgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gLjkpLAogICMgICB3aWR0aCA9IC4zKSArCiAgZmFjZXRfd3JhcCguIH4gY29tcG9uZW50LCBzY2FsZXMgPSAiZnJlZSIpICsKICB5bGFiKCJtZWFuIGFnZSIpICsKICB0aGVtZV9idygpICsKICB0aGVtZShwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpKQpgYGAKCiMjIyBCYXllc2lhbiBwYXJhbWV0ZXIgZXN0aW1hdGlvbiAoTUNNQykKCmBgYHtyIE1DTUMtZml0cywgZXZhbCA9IEZBTFNFfQojIHRoZSBmb2xsb3dpbmcgLlJEYXRhIGZpbGVzIGFyZSBnZW5lcmF0ZWQgYnkgc2NyaXB0ICJzcmEtdHMvc291cmNlL3NyYS10cy0xNGMtbWNtYy1iYXllcy5SIgpsb2FkKGZpbGUgPSAiLi4vZGF0YS9kZXJpdmVkL2JheWVzLXBhci1maXQtMjAyMC0xMS0wNi9iYXllc19maXRfMnBwXzAtMTBfNTAwMGl0ZXIuUkRhdGEiKQpsb2FkKGZpbGUgPSAiLi4vZGF0YS9kZXJpdmVkL2JheWVzLXBhci1maXQtMjAyMC0xMS0xNy9iYXllc19maXRfMnBzXzAtMTBfNTAwMGl0ZXIuUkRhdGEiKQoKIyAjIHBsb3QgcGFyYW1ldGVyIGNvbnZlcmdlbmNlCiMgbGFwcGx5KGJheWVzX2ZpdF8ycHBfMF8xMCwgcGxvdCkKIyBsYXBwbHkoYmF5ZXNfZml0XzJwc18wXzEwLCBwbG90KQoKIyBwbG90IGNvbGxpbmVhcml0eQppdGVyIDwtIDUwMDAKbGFwcGx5KGJheWVzX2ZpdF8ycHBfMF8xMCwgcGFpcnMsIG5zYW1wbGUgPSBmbG9vcihpdGVyLzQpKQpsYXBwbHkoYmF5ZXNfZml0XzJwc18wXzEwLCBwYWlycywgbnNhbXBsZSA9IGZsb29yKGl0ZXIvNCkpCgojIyBsb29rIGF0IG1vZGVsIHBlcmZvcm1hbmNlCnBhcnMuYmF5ZXMuZGYuZnggPC0gZnVuY3Rpb24obW9kLCBwYXJzLmJheWVzLCBwYXJzLmZpdCkgewogIGJpbmRfcm93cyhsYXBwbHkoc2VxX2Fsb25nKHBhcnMuYmF5ZXMpLCBmdW5jdGlvbihpKSB7CiAgICBpeCA8LSBtYXRjaCh1bmlxdWUocGFycy5iYXllc1tbaV1dW1sicGFycyJdXVssIDFdKSwgcGFycy5iYXllc1tbaV1dW1sicGFycyJdXVssIDFdKQogICAgZGYgPC0gZGF0YS5mcmFtZShrMSA9IHBhcnMuYmF5ZXNbW2ldXVtbInBhcnMiXV1baXgsIDFdLAogICAgICAgICAgICAgICAgICAgICBrMiA9IHBhcnMuYmF5ZXNbW2ldXVtbInBhcnMiXV1baXgsIDJdLAogICAgICAgICAgICAgICAgICAgICBwMyA9IHBhcnMuYmF5ZXNbW2ldXVtbInBhcnMiXV1baXgsIDNdKQogICAgZGYgPC0gY2JpbmQoZGYsCiAgICAgICAgICAgICAgICBQTWVjb19kZXB0aCA9IHJlcChuYW1lcyhwYXJzLmZpdClbaV0sIGxlbmd0aChpeCkpLAogICAgICAgICAgICAgICAgbW9kID0gcmVwKG1vZCwgbGVuZ3RoKGl4KSkpCiAgICBkZiA8LSBjYmluZChkZiwgCiAgICAgICAgICAgICAgICBQTSA9IGZhY3RvcihzdWJzdHIoZGYkUE1lY29fZGVwdGgsIDEsIDIpKSwKICAgICAgICAgICAgICAgIGVjbyA9IGZhY3RvcihzdWJzdHIoZGYkUE1lY29fZGVwdGgsIDMsIDQpLCBsZXZlbHMgPSBjKCJwcCIsICJ3ZiIsICJyZiIpKSkKICAgIHJldHVybihkZikKICB9KSkKfQpwYXJzLmJheWVzLjJwcC5kZiA8LSBwYXJzLmJheWVzLmRmLmZ4KCIycHAiLCBiYXllc19maXRfMnBwXzBfMTAsIHBhcnMuZml0LjJwcCkKcGFycy5iYXllcy4ycHMuZGYgPC0gcGFycy5iYXllcy5kZi5meCgiMnBzIiwgYmF5ZXNfZml0XzJwc18wXzEwLCBwYXJzLmZpdC4ycHMpCgojICMgbGluZWFyIGZpdHMKIyBzdW1tYXJ5KGxtKGsyIH4gUE0sIHBhcnMuYmF5ZXMuMnBwLmRmKSkKIyBzdW1tYXJ5KGxtKGsyIH4gZWNvLCBwYXJzLmJheWVzLjJwcC5kZikpCiMgc3VtbWFyeShsbShrMSB+IFBNLCBwYXJzLmJheWVzLjJwcC5kZikpCiMgc3VtbWFyeShsbShrMSB+IGVjbywgcGFycy5iYXllcy4ycHAuZGYpKQojIHN1bW1hcnkobG0ocDMgfiBQTSwgcGFycy5iYXllcy4ycHAuZGYpKQojIHN1bW1hcnkobG0ocDMgfiBlY28sIHBhcnMuYmF5ZXMuMnBwLmRmKSkKCiMgYmVzdCBwYXIgc2V0CmJlc3RQYXJzLmJheWVzLmxzIDwtIGxhcHBseShiYXllc19maXRfMnBwXzBfMTAsIGZ1bmN0aW9uKHgpIHsKICByb3VuZChkYXRhLmZyYW1lKGsxID0geCRiZXN0cGFyWzFdLAogICAgICAgICAgICAgICAgICAgazIgPSB4JGJlc3RwYXJbMl0sCiAgICAgICAgICAgICAgICAgICBnYW0gPSB4JGJlc3RwYXJbM10pLAogICAgICAgIDQpCn0pCmJlc3RQYXJzLmJheWVzLmRmIDwtIGNiaW5kKFBNID0gcmVwKGMoIkFOIiwgIkJTIiwgIkdSIiksIGVhY2ggPSAzKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgZWNvID0gcmVwKGMoInBwIiwgInJmIiwgIndmIiksIDMpLAogICAgICAgICAgICAgICAgICAgICAgICAgICBkZXB0aCA9IHJlcCgiMC0xMCIsIDkpLAogICAgICAgICAgICAgICAgICAgICAgICAgICBiaW5kX3Jvd3MoYmVzdFBhcnMuYmF5ZXMubHMpKQoKIyBzdW1tYXJpemUgYnkgUE0KcGFycy5iYXllcy5QTSA8LSBiZXN0UGFycy5iYXllcy5kZiAlPiUKICBzZWxlY3QoIWMoZWNvLCBkZXB0aCkpICU+JQogIGdyb3VwX2J5KFBNKSAlPiUKICBzdW1tYXJpemVfYWxsKGxpc3QobWVhbiA9IG1lYW4sIHNkID0gc2QpKSAlPiUKICBtdXRhdGVfaWYoaXMubnVtZXJpYywgZm9ybWF0LCBkaWdpdHMgPSAzKQojIHN1bW1hcml6ZSBieSBFQ08KcGFycy5iYXllcy5lY28gPC0gYmVzdFBhcnMuYmF5ZXMuZGYgJT4lCiAgc2VsZWN0KCFjKFBNLCBkZXB0aCkpICU+JQogIGdyb3VwX2J5KGVjbykgJT4lCiAgc3VtbWFyaXplX2FsbChsaXN0KG1lYW4gPSBtZWFuLCBzZCA9IHNkKSkgJT4lCiAgbXV0YXRlX2lmKGlzLm51bWVyaWMsIGZvcm1hdCwgZGlnaXRzID0gMykKCiMgcGxvdCBiZXN0IHBhcnMKYmVzdFBhcnMuYmF5ZXMuZGYgJT4lCiAgcGl2b3RfbG9uZ2VyKCEoUE06ZGVwdGgpLCBuYW1lc190byA9ICJwYXIiLCB2YWx1ZXNfdG8gPSAidmFsdWUiKSAlPiUKICBtdXRhdGUoUE0gPSBmYWN0b3IoUE0pLAogICAgICAgICBlY28gPSBmYWN0b3IoZWNvLCBsZXZlbHMgPSBjKCJwcCIsICJ3ZiIsICJyZiIpKSkgJT4lCiAgZ2dwbG90KC4sIGFlcyhwYXIsIHZhbHVlLCBjb2xvciA9IFBNLCBzaGFwZSA9IGVjbykpICsKICBnZW9tX2ppdHRlcihzaXplID0gNCkgKwogIHNjYWxlX2NvbG9yX21hbnVhbChuYW1lID0gInBhcmVudCBtYXRlcmlhbCIsCiAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiQU4iID0gImFuZGVzaXRlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJCUyIgPSAiYmFzYWx0IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJHUiIgPSAiZ3Jhbml0ZSIpLAogICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9IGMoIkFOIiA9ICJibHVlIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQlMiID0gInJlZCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkdSIiA9ICJkYXJrZ3JheSIpKSArCiAgZmFjZXRfd3JhcCguIH4gcGFyLCBzY2FsZXMgPSAiZnJlZSIpICsKICB0aGVtZV9idygpICsKICB0aGVtZShwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpKQoKIyBwbG90IGFjY2VwdGVkIHBhcnMgYnkgUE0gYW5kIHRoZW4gYnkgZWNvCnBhcnMuYmF5ZXMuZGYgJT4lCiAgcGl2b3RfbG9uZ2VyKCFjKFBNLCBlY28sIFBNZWNvX2RlcHRoKSwgbmFtZXNfdG8gPSAicGFyIiwgdmFsdWVzX3RvID0gInZhbHVlIikgJT4lCiAgbXV0YXRlKFBNID0gZmFjdG9yKFBNKSwKICAgICAgICAgZWNvID0gZmFjdG9yKGVjbywgbGV2ZWxzID0gYygicHAiLCAid2YiLCAicmYiKSkpICU+JQogIGdncGxvdCguLCBhZXMocGFyLCB2YWx1ZSwgZmlsbCA9IFBNKSkgKwogIGdlb21fYm94cGxvdCgpICsKICBzY2FsZV9maWxsX21hbnVhbChuYW1lID0gInBhcmVudCBtYXRlcmlhbCIsCiAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiQU4iID0gImFuZGVzaXRlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJCUyIgPSAiYmFzYWx0IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJHUiIgPSAiZ3Jhbml0ZSIpLAogICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9IGMoIkFOIiA9ICJibHVlIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQlMiID0gInJlZCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkdSIiA9ICJkYXJrZ3JheSIpKSArCiAgZmFjZXRfd3JhcCguIH4gcGFyLCBzY2FsZXMgPSAiZnJlZSIpICsKICB0aGVtZV9idygpICsKICB0aGVtZShwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpKQpwYXJzLmJheWVzLmRmICU+JQogIHBpdm90X2xvbmdlcighYyhQTSwgZWNvLCBQTWVjb19kZXB0aCksIG5hbWVzX3RvID0gInBhciIsIHZhbHVlc190byA9ICJ2YWx1ZSIpICU+JQogIG11dGF0ZShQTSA9IGZhY3RvcihQTSksCiAgICAgICAgIGVjbyA9IGZhY3RvcihlY28sIGxldmVscyA9IGMoInBwIiwgIndmIiwgInJmIikpKSAlPiUKICBnZ3Bsb3QoLiwgYWVzKHBhciwgdmFsdWUsIGZpbGwgPSBlY28pKSArCiAgZ2VvbV9ib3hwbG90KCkgKwogIGZhY2V0X3dyYXAoLiB+IHBhciwgc2NhbGVzID0gImZyZWUiKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUocGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSkKYGBg